assistant-runtime-sdk 1.0.1__tar.gz → 1.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: assistant_runtime_sdk
3
- Version: 1.0.1
3
+ Version: 1.2.0
4
4
  Summary: Python SDK for FAC Cloud - the Assistant Runtime AI assistant backend
5
5
  Keywords: frappe,ai,assistant,llm,mcp,anthropic,openai,streaming
6
6
  Author: Paul Clinton
@@ -157,8 +157,9 @@ surface. A representative selection:
157
157
  `create_message()`, `update_conversation()`, `delete_conversation()`, `delete_message()`
158
158
 
159
159
  **Billing** — `get_plan_comparison()`, `get_usage_dashboard()`, `get_usage_history()`,
160
- `get_credit_balance()`, `initiate_checkout()`, `verify_checkout()`, `upgrade_plan()`,
161
- `cancel_subscription()`, `get_invoices()`
160
+ `get_credit_balance()`, `initiate_checkout()`, `create_hosted_checkout()`,
161
+ `verify_checkout()`, `upgrade_plan()`, `cancel_subscription()`, `get_invoices()`,
162
+ `get_payment_instrument()`, `update_payment_method()`
162
163
 
163
164
  **Users & seats** — `register_user()`, `get_user()`, `list_users()`, `invite_user()`,
164
165
  `add_user_seat()`, `set_user_credit_limit()`, `get_user_auth_status()`
@@ -124,8 +124,9 @@ surface. A representative selection:
124
124
  `create_message()`, `update_conversation()`, `delete_conversation()`, `delete_message()`
125
125
 
126
126
  **Billing** — `get_plan_comparison()`, `get_usage_dashboard()`, `get_usage_history()`,
127
- `get_credit_balance()`, `initiate_checkout()`, `verify_checkout()`, `upgrade_plan()`,
128
- `cancel_subscription()`, `get_invoices()`
127
+ `get_credit_balance()`, `initiate_checkout()`, `create_hosted_checkout()`,
128
+ `verify_checkout()`, `upgrade_plan()`, `cancel_subscription()`, `get_invoices()`,
129
+ `get_payment_instrument()`, `update_payment_method()`
129
130
 
130
131
  **Users & seats** — `register_user()`, `get_user()`, `list_users()`, `invite_user()`,
131
132
  `add_user_seat()`, `set_user_credit_limit()`, `get_user_auth_status()`
@@ -53,7 +53,7 @@ Standalone Functions:
53
53
 
54
54
  """
55
55
 
56
- __version__ = "1.0.1"
56
+ __version__ = "1.2.0"
57
57
  __author__ = "Paul Clinton"
58
58
  __license__ = "AGPL-3.0"
59
59
 
@@ -872,6 +872,16 @@ class AsyncAssistantRuntimeClient(BaseAssistantRuntimeClient):
872
872
  endpoint, payload = self._prepare_initiate_checkout(plan, billing_cycle, gateway, billing_name, billing_email)
873
873
  return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
874
874
 
875
+ async def create_hosted_checkout(
876
+ self,
877
+ purpose: str,
878
+ params: Optional[Dict[str, Any]] = None,
879
+ return_url: Optional[str] = None,
880
+ ) -> Optional[Dict[str, Any]]:
881
+ """Async version of AssistantRuntimeClient.create_hosted_checkout."""
882
+ endpoint, payload = self._prepare_create_hosted_checkout(purpose, params, return_url)
883
+ return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
884
+
875
885
  async def verify_checkout(self, session_id: Optional[str] = None) -> Optional[Dict[str, Any]]:
876
886
  """Async version of AssistantRuntimeClient.verify_checkout."""
877
887
  endpoint, payload = self._prepare_verify_checkout(session_id)
@@ -951,6 +961,11 @@ class AsyncAssistantRuntimeClient(BaseAssistantRuntimeClient):
951
961
  endpoint, payload = self._prepare_get_payment_methods()
952
962
  return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
953
963
 
964
+ async def get_payment_instrument(self) -> Optional[Dict[str, Any]]:
965
+ """Async version of AssistantRuntimeClient.get_payment_instrument."""
966
+ endpoint, payload = self._prepare_get_payment_instrument()
967
+ return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
968
+
954
969
  async def upgrade_plan(
955
970
  self,
956
971
  new_plan: str,
@@ -1020,9 +1035,16 @@ class AsyncAssistantRuntimeClient(BaseAssistantRuntimeClient):
1020
1035
  endpoint, payload = self._prepare_resume_subscription()
1021
1036
  return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
1022
1037
 
1023
- async def update_payment_method(self) -> Optional[Dict[str, Any]]:
1038
+ async def update_payment_method(
1039
+ self,
1040
+ payment_method: Optional[str] = None,
1041
+ billing_name: Optional[str] = None,
1042
+ ) -> Optional[Dict[str, Any]]:
1024
1043
  """Async version of AssistantRuntimeClient.update_payment_method."""
1025
- endpoint, payload = self._prepare_update_payment_method()
1044
+ endpoint, payload = self._prepare_update_payment_method(
1045
+ payment_method=payment_method,
1046
+ billing_name=billing_name,
1047
+ )
1026
1048
  return await self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
1027
1049
 
1028
1050
  async def get_subscription_status(self) -> Optional[Dict[str, Any]]:
@@ -906,6 +906,20 @@ class BaseAssistantRuntimeClient:
906
906
  payload["billing_email"] = billing_email
907
907
  return "initiate_checkout", payload
908
908
 
909
+ def _prepare_create_hosted_checkout(
910
+ self, purpose: str, params: Optional[Dict[str, Any]] = None,
911
+ return_url: Optional[str] = None,
912
+ ) -> tuple:
913
+ self._require_billing()
914
+ payload: Dict[str, Any] = {
915
+ "tenant_id": self.tenant_id,
916
+ "purpose": purpose,
917
+ "params": params or {},
918
+ }
919
+ if return_url:
920
+ payload["return_url"] = return_url
921
+ return "create_hosted_checkout", payload
922
+
909
923
  def _prepare_verify_checkout(self, session_id: Optional[str] = None) -> tuple:
910
924
  self._require_billing()
911
925
  payload: Dict[str, Any] = {"tenant_id": self.tenant_id}
@@ -989,6 +1003,12 @@ class BaseAssistantRuntimeClient:
989
1003
  self._require_billing()
990
1004
  return "get_payment_methods", {"tenant_id": self.tenant_id}
991
1005
 
1006
+ def _prepare_get_payment_instrument(self) -> tuple:
1007
+ """Build the request for ``get_payment_instrument`` — the instrument
1008
+ on file for autopay, plus how it can be changed."""
1009
+ self._require_billing()
1010
+ return "get_payment_instrument", {"tenant_id": self.tenant_id}
1011
+
992
1012
  def _prepare_upgrade_plan(
993
1013
  self, new_plan: str, billing_cycle: str = "monthly",
994
1014
  gateway: Optional[str] = None, billing_name: Optional[str] = None,
@@ -1070,9 +1090,24 @@ class BaseAssistantRuntimeClient:
1070
1090
  self._require_billing()
1071
1091
  return "resume_subscription", {"tenant_id": self.tenant_id}
1072
1092
 
1073
- def _prepare_update_payment_method(self) -> tuple:
1093
+ def _prepare_update_payment_method(
1094
+ self,
1095
+ payment_method: Optional[str] = None,
1096
+ billing_name: Optional[str] = None,
1097
+ ) -> tuple:
1098
+ """Build the request for ``update_payment_method``.
1099
+
1100
+ Optional values are omitted rather than sent as null: the endpoint
1101
+ derives its own defaults (UPI for India, card otherwise), and an
1102
+ explicit null would override that with nothing.
1103
+ """
1074
1104
  self._require_billing()
1075
- return "update_payment_method", {"tenant_id": self.tenant_id}
1105
+ payload: Dict[str, Any] = {"tenant_id": self.tenant_id}
1106
+ if payment_method:
1107
+ payload["payment_method"] = payment_method
1108
+ if billing_name:
1109
+ payload["billing_name"] = billing_name
1110
+ return "update_payment_method", payload
1076
1111
 
1077
1112
  def _prepare_get_subscription_status(self) -> tuple:
1078
1113
  self._require_billing()
@@ -1238,6 +1238,34 @@ class AssistantRuntimeClient(BaseAssistantRuntimeClient):
1238
1238
  endpoint, payload = self._prepare_initiate_checkout(plan, billing_cycle, gateway, billing_name, billing_email)
1239
1239
  return self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
1240
1240
 
1241
+ def create_hosted_checkout(
1242
+ self,
1243
+ purpose: str,
1244
+ params: Optional[Dict[str, Any]] = None,
1245
+ return_url: Optional[str] = None,
1246
+ ) -> Optional[Dict[str, Any]]:
1247
+ """
1248
+ Get a link to the page where a purchase is paid for.
1249
+
1250
+ Payments are collected on the runtime's own public site rather than
1251
+ on this one, so that a payment gateway can be onboarded against a
1252
+ single declared address. Send the user to ``checkout_url``; they are
1253
+ returned to ``return_url`` when they are done.
1254
+
1255
+ Args:
1256
+ purpose: "Subscription", "Payment Method", "Credits", "Pack" or "Seat".
1257
+ params: Purpose-specific arguments — e.g. ``{"plan": "Team",
1258
+ "billing_cycle": "monthly"}`` for a subscription, or
1259
+ ``{"credit_amount": 5000}`` for credits.
1260
+ return_url: Where to send the user afterwards. Must be on this
1261
+ site; defaults to the registered site URL.
1262
+
1263
+ Returns:
1264
+ Dict with checkout_url, session, purpose and expires_at.
1265
+ """
1266
+ endpoint, payload = self._prepare_create_hosted_checkout(purpose, params, return_url)
1267
+ return self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
1268
+
1241
1269
  def verify_checkout(self, session_id: Optional[str] = None) -> Optional[Dict[str, Any]]:
1242
1270
  """Verify payment completion after checkout."""
1243
1271
  endpoint, payload = self._prepare_verify_checkout(session_id)
@@ -1375,6 +1403,51 @@ class AssistantRuntimeClient(BaseAssistantRuntimeClient):
1375
1403
  endpoint, payload = self._prepare_get_payment_methods()
1376
1404
  return self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
1377
1405
 
1406
+ def get_payment_instrument(self) -> Optional[Dict[str, Any]]:
1407
+ """Get the instrument on file for automatic payments.
1408
+
1409
+ One shape regardless of gateway — callers never need to branch on
1410
+ ``gateway`` to read ``autopay``. Fields that only apply to Razorpay
1411
+ (``mandate``, ``max_amount``, ``authorized_on``, ``needs_reauth``,
1412
+ ``vpa``, ``bank``, and ``card.issuer``) are ``None`` on Stripe, not
1413
+ omitted.
1414
+
1415
+ Returns:
1416
+ {
1417
+ "gateway": "razorpay" | "stripe",
1418
+ "autopay": {
1419
+ "mandate": str | None, # Razorpay only
1420
+ "status": str,
1421
+ "method": "upi" | "card" | "emandate",
1422
+ "label": str, # "UPI Autopay"
1423
+ "display": str, # "paul@okhdfcbank" / "Visa •••• 4242"
1424
+ "card": {
1425
+ "last4": str | None,
1426
+ "network": str | None,
1427
+ "issuer": str | None, # Razorpay only
1428
+ "expiry": str | None, # "MM/YYYY"
1429
+ } | None,
1430
+ "vpa": str | None, # Razorpay UPI only
1431
+ "bank": str | None, # Razorpay only
1432
+ "max_amount": float | None, # per-debit ceiling, Razorpay only
1433
+ "currency": str,
1434
+ "authorized_on": str | None, # Razorpay only
1435
+ "next_charge_date": str | None,
1436
+ "needs_reauth": bool | None, # Razorpay only
1437
+ "suspended": bool,
1438
+ } | None, # None when no instrument is on file
1439
+ "can_update": bool,
1440
+ "update_mode": "settle" | "swap" | "portal",
1441
+ "amount_due": {"invoice", "amount", "currency"} | None,
1442
+ }
1443
+
1444
+ ``update_mode`` tells the caller what ``update_payment_method`` will
1445
+ do: settle an outstanding invoice, swap the saved instrument, or
1446
+ hand back a Stripe portal URL.
1447
+ """
1448
+ endpoint, payload = self._prepare_get_payment_instrument()
1449
+ return self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
1450
+
1378
1451
  def upgrade_plan(
1379
1452
  self,
1380
1453
  new_plan: str,
@@ -1487,9 +1560,40 @@ class AssistantRuntimeClient(BaseAssistantRuntimeClient):
1487
1560
  endpoint, payload = self._prepare_resume_subscription()
1488
1561
  return self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
1489
1562
 
1490
- def update_payment_method(self) -> Optional[Dict[str, Any]]:
1491
- """Get URL to update payment method."""
1492
- endpoint, payload = self._prepare_update_payment_method()
1563
+ def update_payment_method(
1564
+ self,
1565
+ payment_method: Optional[str] = None,
1566
+ billing_name: Optional[str] = None,
1567
+ ) -> Optional[Dict[str, Any]]:
1568
+ """Change the instrument that pays for this subscription.
1569
+
1570
+ What this does depends on whether anything is owed, which the
1571
+ server decides — call ``get_payment_instrument`` first if you need
1572
+ to know in advance:
1573
+
1574
+ - An unpaid renewal exists: the returned Razorpay checkout settles
1575
+ *that* invoice at the amount it was billed for and registers the
1576
+ new instrument for autopay in the same authorization. The billing
1577
+ period does not move. ``amount_due`` carries the figure.
1578
+ - Nothing is owed: the checkout debits one currency unit purely to
1579
+ register the token, refunded automatically on capture.
1580
+ - Stripe: returns ``portal_url`` for the Customer Portal.
1581
+
1582
+ Args:
1583
+ payment_method: Razorpay only — "upi" (UPI Autopay) or "card".
1584
+ Defaults to "upi" for India, "card" for international.
1585
+ billing_name: Name to prefill in the checkout widget.
1586
+
1587
+ Returns:
1588
+ Razorpay: the checkout payload (``razorpay_key``,
1589
+ ``razorpay_order_id``, ``amount``, ``currency``, ``prefill``, …)
1590
+ plus ``update_mode`` and, when settling, ``amount_due``.
1591
+ Stripe: ``{"update_mode": "portal", "portal_url": str}``.
1592
+ """
1593
+ endpoint, payload = self._prepare_update_payment_method(
1594
+ payment_method=payment_method,
1595
+ billing_name=billing_name,
1596
+ )
1493
1597
  return self._request_post_json(endpoint, payload, api_base=self.billing_api_base)
1494
1598
 
1495
1599
  def get_subscription_status(self) -> Optional[Dict[str, Any]]:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "assistant_runtime_sdk"
3
- version = "1.0.1"
3
+ version = "1.2.0"
4
4
  description = "Python SDK for FAC Cloud - the Assistant Runtime AI assistant backend"
5
5
  readme = "README.md"
6
6
  license = {text = "AGPL-3.0"}