Metadata-Version: 2.4
Name: paython-wrapper
Version: 3.0.0
Summary: PayPayモバイルAPIの非公式Pythonラッパー
Author: wieweiwie8878-wq
License: All Rights Reserved
Project-URL: Homepage, https://github.com/wieweiwie8878-wq/paython-wrapper
Project-URL: Source, https://github.com/wieweiwie8878-wq/paython-wrapper
Keywords: paypay,mobile,api,wrapper,payment
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: Other/Proprietary License
Classifier: Natural Language :: Japanese
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
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: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests
Requires-Dist: pkce
Dynamic: license-file

# paython-wrapper

PayPayモバイルAPIの非公式Pythonラッパー。Python 3.10+。

![Python](https://img.shields.io/badge/Python-3.10+-blue)
![License](https://img.shields.io/badge/License-All_Rights_Reserved-red)

## 📦 インストール

```bash
pip install requests pkce
```

---

## 🔐 ログイン

| 方法 | コード |
|------|--------|
| **新規ログイン**<br>電話＋パスワード＋SMSリンク | `PayPay("tel", "pass")` → SMSのURLを `login()` に渡す |
| **デバイスUUID指定**<br>SMS不要 | `PayPay("tel", "pass", device_uuid=...)` |
| **アクセストークンのみ**<br>ログイン処理スキップ | `PayPay(access_token=...)` |
| **トークンリフレッシュ**<br>90日ごと | `p.token_refresh("refresh_token")` |

```python
from paython_wrapper import PayPay

# ── 新規ログイン ──
paypay = PayPay("080-1234-5678", "パスワード")
url = input("SMSのURL: ")
paypay.login(url)

print("access_token :", paypay.access_token)
print("refresh_token:", paypay.refresh_token)
print("device_uuid  :", paypay.device_uuid)

# ── アクセストークンからの復帰 ──
paypay = PayPay(access_token="保存しておいたトークン")

# ── トークンリフレッシュ ──
paypay = PayPay(access_token="古いトークン")
paypay.token_refresh("リフレッシュトークン")
print("新しいアクセストークン:", paypay.access_token)
```

> SMSのURLは `https://www.paypay.ne.jp/portal/oauth2/l?id=TK4602` をそのまま。末尾のIDだけでもOK。

---

## 📚 機能一覧

<details>
<summary><strong>👤 プロフィール</strong></summary>

```python
profile = paypay.get_profile()
print(profile.name)
print(profile.external_user_id)
print(profile.icon)
```
</details>

<details>
<summary><strong>💰 残高</strong></summary>

```python
bal = paypay.get_balance()
print("全残高:", bal.all_balance)
print("マネーライト:", bal.money_light, "／ マネー:", bal.money)
print("ポイント:", bal.points)
print("使用可能:", bal.usable_balance)
```
</details>

<details>
<summary><strong>📜 入出金履歴・ポイント履歴</strong></summary>

```python
paypay.get_history(size=20)           # 入出金履歴
paypay.get_history(size=20, cashback=True)  # キャッシュバックのみ
paypay.get_point_history()            # ポイント履歴
```
</details>

<details>
<summary><strong>🔗 送金リンク</strong></summary>

```python
# 確認
info = paypay.link_check("KT975hvzbH1EulTr")
print(info.amount, info.status, info.sender_name)

# URL直接でもOK
paypay.link_check("https://pay.paypay.ne.jp/KT975hvzbH1EulTr")

# ログイン不要で確認（web_api版）
paypay.link_check("KT975hvzbH1EulTr", web_api=True)

# 作成
link = paypay.create_link(amount=100, passcode="4602")
print(link.link)
paypay.create_link(amount=100, pochibukuro=True)  # ポチ袋

# 受け取り／辞退／キャンセル
paypay.link_receive("KT975hvzbH1EulTr", passcode="4602")
paypay.link_reject("KT975hvzbH1EulTr")
paypay.link_cancel("KT975hvzbH1EulTr")
```
> link_checkで取得した `link_info` を receive/reject/cancel に渡すと内部の確認処理をスキップして速くなります。
</details>

<details>
<summary><strong>💸 送金・QRコード</strong></summary>

```python
# P2Pコード作成（自分宛QR）
code = paypay.create_p2pcode(amount=100)
print(code.p2pcode)

# 直接送金
result = paypay.send_money(amount=100, receiver_id="相手のexternal_user_id")
print(result.chat_room_id)
```
</details>

<details>
<summary><strong>💬 メッセージ（PayPay内DM）</strong></summary>

```python
# チャットルーム一覧
paypay.get_chat_rooms(size=20)

# メッセージ取得（prev=Nで過去N件）
paypay.get_chat_room_messages("sendbird_group_channel_xxxxx", prev=15)

# メッセージ送信
paypay.send_message("チャットルームID", "ありがとうございます！")

# DM用チャットルーム作成（ExternalUserIDから）
room = paypay.initialize_chatroom("相手のExternalUserID")
print(room.chatroom_id)
```
</details>

<details>
<summary><strong>🔍 ユーザー検索</strong></summary>

```python
# グローバル検索（PayPay ID）
user = paypay.search_p2puser(user_id="ユーザーID")

# フレンド検索（表示名）
user = paypay.search_p2puser(user_id="表示名", is_global=False, order=0)
```
> グローバル検索はすぐにレート制限にかかります。連続検索は避けてください。
</details>

<details>
<summary><strong>📷 バーコード情報</strong></summary>

```python
info = paypay.get_barcode_info("https://qr.paypay.ne.jp/.............")
print(info.amount, info.user_name, info.external_user_id)
```
</details>

<details>
<summary><strong>⚙️ 設定・出金</strong></summary>

```python
# 残高優先度（False=マネーライト優先 / True=マネー優先）
paypay.set_money_priority(paypay_money=False)

# PayPay銀行に出金
result = paypay.cashout_to_paypaybank(amount=1000)
print(result.bank_name, result.bank_account_number)
```
</details>

<details>
<summary><strong>🤖 Bot検知回避（alive）</strong></summary>

```python
paypay.alive()
# 引数・戻り値なし。定期的に呼ぶとBot判定されにくくなります。
```
</details>

---

## 🧬 戻り値の型

各メソッドは NamedTuple を返します。生レスポンスは `.raw`。

<details>
<summary><strong>Profile</strong></summary>

| フィールド | 型 | 説明 |
|-----------|----|------|
| name | str | ユーザー表示名 |
| external_user_id | str | 識別用ユーザーID |
| icon | str | アイコンURL |
| raw | dict | 生レスポンス |
</details>

<details>
<summary><strong>Balance</strong></summary>

| フィールド | 型 | 説明 |
|-----------|----|------|
| money | int \| None | マネー残高 |
| money_light | int | マネーライト |
| all_balance | int | 合計 |
| usable_balance | int | 使用可能 |
| points | int | ポイント |
| raw | dict | 生レスポンス |
</details>

<details>
<summary><strong>LinkInfo（link_check）</strong></summary>

| フィールド | 型 | 説明 |
|-----------|----|------|
| sender_name | str | 送信者名 |
| sender_external_user_id | str | 送信者ID |
| sender_icon | str | 送信者アイコン |
| order_id | str | 注文ID |
| chat_room_id | str | チャットルームID |
| amount | int | 金額 |
| status | str | PENDING / COMPLEATED / REJECTED / FAILED |
| money_light | int | マネーライト充当額 |
| money | int | マネー充当額 |
| has_password | bool | パスワード設定有無 |
| raw | dict | 生レスポンス |
</details>

<details>
<summary><strong>CreatedLink</strong></summary>

| フィールド | 型 | 説明 |
|-----------|----|------|
| link | str | 送金リンクURL |
| chat_room_id | str | チャットルームID |
| order_id | str | 注文ID |
| raw | dict | 生レスポンス |
</details>

<details>
<summary><strong>SendMoneyResult</strong></summary>

| フィールド | 型 | 説明 |
|-----------|----|------|
| chat_room_id | str | チャットルームID |
| order_id | str | 注文ID |
| raw | dict | 生レスポンス |
</details>

<details>
<summary><strong>P2PCode / P2PUser / ChatRoom / BarcodeInfo / CashoutResult</strong></summary>

**P2PCode**: `p2pcode`(str), `raw`  
**P2PUser**: `name`(str), `icon`(str), `external_user_id`(str), `raw`  
**ChatRoom**: `chatroom_id`(str), `raw`  
**BarcodeInfo**: `amount`(int\|None), `user_name`(str), `external_user_id`(str), `user_icon`(str), `raw`  
**CashoutResult**: `bank_name`(str), `bank_account_type`(str), `bank_branch_name`(str), `bank_account_number`(str)
</details>

---

## 🌐 プロキシ

```python
# 文字列
PayPay("tel", "pass", proxy="http://host:port")

# 辞書
PayPay("tel", "pass", proxy={"http": "...", "https": "..."})

# デフォルト（プロキシなし）
PayPay("tel", "pass", proxy=None)
```

---

## 💾 トークンの保存と再利用

```python
import json

# ログイン
paypay = PayPay("080-1234-5678", "パスワード")
paypay.login(input("URL: "))

# 保存
token_data = {
    "access_token": paypay.access_token,
    "refresh_token": paypay.refresh_token,
    "device_uuid": paypay.device_uuid,
}
json.dump(token_data, open("tokens.json", "w"))

# 復元
token_data = json.load(open("tokens.json"))
paypay = PayPay(access_token=token_data["access_token"])

# 失効していたらリフレッシュ
try:
    paypay.get_balance()
except PayPayLoginError:
    paypay.token_refresh(token_data["refresh_token"])
    json.dump({"access_token": paypay.access_token, "refresh_token": paypay.refresh_token}, open("tokens.json", "w"))
```

---

## ⚠️ エラー

| 例外 | 意味 |
|------|------|
| `PayPayError` | 基底例外。APIエラー全般 |
| `PayPayLoginError` | 認証エラー / トークン失効 |
| `PayPayNetworkError` | ネットワークエラー / 国外ブロック |
| `P2PTemporaryHoldError` | P2P一時保留（42007013） |

```python
from paython_wrapper import PayPay, PayPayLoginError, PayPayNetworkError, P2PTemporaryHoldError

try:
    paypay = PayPay("080-1234-5678", "pass")
    paypay.login(input("URL: "))
except PayPayNetworkError:
    print("日本からアクセスしていますか？")
except PayPayLoginError:
    print("ログイン失敗。3回失敗でアカウントロックされます。")

try:
    paypay.link_receive("リンクID", passcode="4602")
except P2PTemporaryHoldError:
    print("一時保留中。時間をおいて再試行。")
except PayPayLoginError:
    print("トークン失効。リフレッシュしてください。")
```

---

## ⚡ 注意事項

- **ログイン3回失敗でアカウント一時ロック** — PayPayサポートに連絡すると解除される場合あり
- **日本IP必須** — 海外サーバー利用時はプロキシ必須
- **アクセストークンは90日で失効** — リフレッシュトークンで更新可能
- **Bot検知に注意** — `alive()` を定期的に呼ぶことを推奨
- **端末センサーデータをランダム生成して送信** — Bot検知回避のため

---

## ❓ Q&A

**Q.** 電話番号のハイフンは必要？  
**A.** 不要です。自動処理されます。

**Q.** access_token の有効期限は？  
**A.** 90日です。

**Q.** client_uuid って何？  
**A.** クライアント識別用。指定しなければ自動生成されます。

**Q.** 海外から使えない  
**A.** 日本IP必須です。プロキシを設定してください。

**Q.** Bot検知された  
**A.** `alive()` を定期的に呼んでみてください。頻度を調整すると効果的な場合があります。

**Q.** web_api=True とは？  
**A.** link_checkをログイン不要で実行できます。PayPay()（引数なし）でのインスタンス化も可能です。

---

## 📄 ライセンス

**All Rights Reserved.** Copyright (c) 2026. 再配布・複製を禁じます。
