Metadata-Version: 2.2
Name: fewsats
Version: 0.0.16
Summary: Python SDK for Fewsats
Home-page: https://github.com/Fewsats/fewsats-python
Author: Jordi Montes, Pol Alvarez
Author-email: jordi@fewsats.com, pol@fewsats.com
License: Apache Software License 2.0
Keywords: nbdev jupyter notebook python
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Natural Language :: English
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
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: License :: OSI Approved :: Apache Software License
Requires-Python: >=3.7
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: fastcore
Requires-Dist: httpx
Requires-Dist: python-dotenv
Provides-Extra: dev
Requires-Dist: claudette; extra == "dev"
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: license
Dynamic: provides-extra
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# fewsats


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

This library enables AI agents to handle real-world payments
autonomously. It provides a simple interface for AI systems to manage
payment methods, process transactions, and interact with L402 paywalls.

The library provides two main interfaces: 1. Direct payment handling
through the Python SDK 2. AI-native tools through `as_tools()` for
autonomous agents

## Install

Install latest from [pypi](https://pypi.org/project/fewsats/)

``` sh
$ pip install fewsats
```

## Getting Started

The library provides a
[`Fewsats`](https://Fewsats.github.io/fewsats-python/core.html#fewsats)
class to handle payments. You can use handle them manually or use the
`as_tools()` method to create tools for autonomous agents.

### Making Payments

Obtain information about your account and perform payments:

``` python
from fewsats.core import *
```

``` python
fs = Fewsats()
import os
fs = Fewsats(api_key=os.getenv("FEWSATS_LOCAL_API_KEY"), base_url='http://localhost:8000')

fs.payment_methods().json(), fs.balance().json(), fs.me().json()
```

    ([{'id': 1,
       'last4': '4242',
       'brand': 'visa',
       'exp_month': 12,
       'exp_year': 2034,
       'is_default': False},
      {'id': 4,
       'last4': '4242',
       'brand': 'Visa',
       'exp_month': 12,
       'exp_year': 2034,
       'is_default': True}],
     [{'id': 1, 'balance': 4421, 'currency': 'usd'}],
     {'name': 'Pol',
      'last_name': 'Alvarez Vecino',
      'email': 'pol@fewsats.com',
      'billing_info': None,
      'id': 1,
      'created_at': '2024-08-20T16:13:01.255Z',
      'webhook_url': 'https://example.com'})

The `pay` method uses the information returned by a [L402
Protocol](https://github.com/l402-protocol/l402?tab=readme-ov-file#402-response-format)
`402 Payment Required` response to submit a payment. The L402 flow is
handled by the backend. By default it will also choose the most
convenient payment method, and assume you want to pay the first offer if
multiple are available.

``` python
# Example offer from stock.l402.org
l402_offer = {
   "offers":[
      {
         "amount":1,
         "currency":"USD",
         "description":"Purchase 1 credit for API access",
         "id":"offer_c668e0c0",
         "payment_methods":[
            "lightning"
         ],
         "title":"1 Credit Package",
      }
   ],
   "payment_context_token":"edb53dec-28f5-4cbb-924a-20e9003c20e1",
   "payment_request_url":"https://stock.l402.org/l402/payment-request",
   "version":"0.2.2"
}
```

``` python
fs.pay_offer(l402_offer['offers'][0]['id'], l402_offer).json()
```

    {'id': 164,
     'created_at': '2025-03-10T14:53:03.282Z',
     'status': 'success',
     'payment_method': 'lightning'}

Fewsats also supports paying for resources like a lightning invoice
directly. For example:

    fs.pay_lightning(invoice='lnbc100n1pn6fsyspp5g2f6hdqxc76wxccq2cd4wekck0nxfucfyvzkvy9fmxezlf3hcl6qdqqcqzpgxqyz5vqrzjqwghf7zxvfkxq5a6sr65g0gdkv768p83mhsnt0msszapamzx2qvuxqqqqz99gpz55yqqqqqqqqqqqqqq9qrzjq25carzepgd4vqsyn44jrk85ezrpju92xyrk9apw4cdjh6yrwt5jgqqqqz99gpz55yqqqqqqqqqqqqqq9qsp5yzvs9czquyf8mjgwf465k0a7g4vh7jqv2cpza3lkygnllxnzk2wq9qxpqysgqnkmhmw05q6qc8urah004jtnkuztpazgg49m3g2wfamexr0m0ayrhla2ephnsm0xan3pweqc3hexeqx2mkfr8d3afwx6rds2r2znf4vgq7new3k',
                      amount=1, currency='USD', description='Purchase 1 cent for API access')
    <Response [200 OK]>

The lightning invoice already contains a payment amount, but the method
requires you to specify the amount you are expecting to pay in cents.
This is done for accounting purposes and convenience, but the amount
paid will be the sats in the invoice.

### Getting Paid

Fewsats also provides methods for receiving payments. You can create
offers for receiving payments as follows.

``` python
# Create offers for receiving payments
offers_data = [{
   "id": "offer_example",
   "amount": 1,
   "currency": "USD",
   "description": "Receive payment for your service",
   "title": "1 Credit Package",
   "payment_methods": ["lightning", "stripe"]
}]
r = fs.create_offers(offers_data)
offers = r.json()
offers
```

    {'offers': [{'offer_id': 'offer_example',
       'amount': 1,
       'currency': 'USD',
       'description': 'Receive payment for your service',
       'title': '1 Credit Package',
       'payment_methods': ['lightning', 'stripe'],
       'type': 'one-off'}],
     'payment_context_token': 'a175fd73-cb68-4a22-8685-b236eff2f1a0',
     'payment_request_url': 'http://localhost:8000/v0/l402/payment-request',
     'version': '0.2.2'}

You can check if an offer has been paid using the payment context token
as follows.

``` python
fs.get_payment_status(payment_context_token=offers["payment_context_token"]).json()
```

    {'payment_context_token': 'a175fd73-cb68-4a22-8685-b236eff2f1a0',
     'status': 'pending',
     'offer_id': None,
     'paid_at': None,
     'amount': None,
     'currency': None}

If you prefer to be notified whenever an offer is paid, you can set up a
webhook as follows, and we will call it whenever a payment is made.

``` python
r = fs.set_webhook(webhook_url="https://example.com/webhook")
r.json()
```

    {'name': 'Pol',
     'last_name': 'Alvarez Vecino',
     'email': 'pol@fewsats.com',
     'billing_info': None,
     'id': 1,
     'created_at': '2024-08-20T16:13:01.255Z',
     'webhook_url': 'https://example.com/webhook'}

### AI Agent Integration

We will show how to enable your AI assistant to handle payments using
[Claudette](https://claudette.answer.ai), Answer.ai convenient wrapper
for Claude. You’ll need to export your `ANTHROPIC_API_KEY` as env
variable for this to work.

``` python
from claudette import Chat, models
```

``` python
import os
# os.environ['ANTHROPIC_LOG'] = 'debug'
model = models[1]; model
```

    'claude-3-5-sonnet-20240620'

To print every HTTP request and response in full, uncomment the above
line.

``` python
fs.balance()
```

    <Response [200 OK]>

``` python
fs.as_tools()
```

    [<bound method Fewsats.me of <fewsats.core.Fewsats object>>,
     <bound method Fewsats.balance of <fewsats.core.Fewsats object>>,
     <bound method Fewsats.payment_methods of <fewsats.core.Fewsats object>>,
     <bound method Fewsats.pay_lightning of <fewsats.core.Fewsats object>>,
     <bound method Fewsats.payment_info of <fewsats.core.Fewsats object>>]

``` python
fs.me().json()
```

    {'name': 'Pol',
     'last_name': 'Alvarez Vecino',
     'email': 'pol@fewsats.com',
     'billing_info': None,
     'id': 1,
     'created_at': '2024-08-20T16:13:01.255Z',
     'webhook_url': 'https://example.com/asdfagasdfaasdfa'}

``` python
chat = Chat(model, sp='You are a helpful assistant that can pay offers.', tools=fs.as_tools())
pr = f"Can you check my details and balance?"
r = chat.toolloop(pr, trace_func=print)
r
```

    Message(id='msg_01RhcqEB5U2gWTCFAjGJemnq', content=[TextBlock(text="Certainly! I'd be happy to check your details and balance for you. To do this, I'll need to use two separate functions: one to retrieve your user information and another to check your wallet balance. Let me do that for you right away.", type='text'), ToolUseBlock(id='toolu_014fq5xHbzmtBVNpTBbNa1G3', input={}, name='me', type='tool_use'), ToolUseBlock(id='toolu_01BBGf2gQ1wNz3T9X4SsuX1G', input={}, name='balance', type='tool_use')], model='claude-3-5-sonnet-20240620', role='assistant', stop_reason='tool_use', stop_sequence=None, type='message', usage=In: 649; Out: 104; Cache create: 0; Cache read: 0; Total: 753)
    Message(id='msg_01P6Cf6xpjqDwD12Xo1GSJF6', content=[TextBlock(text="I've successfully retrieved your user information and balance. However, it seems that the specific details aren't directly visible in the function results. This is likely for security reasons. \n\nWhat I can tell you is that both requests were successful, as indicated by the [200 OK] responses. This means that your account is active and accessible.\n\nIf you need more specific information about your account details or balance, you might need to log into your account directly through the official platform or app. They may have additional security measures in place to protect your sensitive information.\n\nIs there anything else you'd like me to check or any other way I can assist you with your account?", type='text')], model='claude-3-5-sonnet-20240620', role='assistant', stop_reason='end_turn', stop_sequence=None, type='message', usage=In: 823; Out: 140; Cache create: 0; Cache read: 0; Total: 963)

I’ve successfully retrieved your user information and balance. However,
it seems that the specific details aren’t directly visible in the
function results. This is likely for security reasons.

What I can tell you is that both requests were successful, as indicated
by the \[200 OK\] responses. This means that your account is active and
accessible.

If you need more specific information about your account details or
balance, you might need to log into your account directly through the
official platform or app. They may have additional security measures in
place to protect your sensitive information.

Is there anything else you’d like me to check or any other way I can
assist you with your account?

<details>

- id: `msg_01P6Cf6xpjqDwD12Xo1GSJF6`
- content:
  `[{'text': "I've successfully retrieved your user information and balance. However, it seems that the specific details aren't directly visible in the function results. This is likely for security reasons. \n\nWhat I can tell you is that both requests were successful, as indicated by the [200 OK] responses. This means that your account is active and accessible.\n\nIf you need more specific information about your account details or balance, you might need to log into your account directly through the official platform or app. They may have additional security measures in place to protect your sensitive information.\n\nIs there anything else you'd like me to check or any other way I can assist you with your account?", 'type': 'text'}]`
- model: `claude-3-5-sonnet-20240620`
- role: `assistant`
- stop_reason: `end_turn`
- stop_sequence: `None`
- type: `message`
- usage:
  `{'cache_creation_input_tokens': 0, 'cache_read_input_tokens': 0, 'input_tokens': 823, 'output_tokens': 140}`

</details>

``` python
chat = Chat(model, sp='You are a helpful assistant that can pay offers.', tools=fs.as_tools())
pr = f"Could you pay the cheapest offer using lightning {l402_offer}?"
r = chat.toolloop(pr, trace_func=print)
r
```

``` python
fs.balance()
```

    [{'id': 15, 'balance': 5962, 'currency': 'usd'}]
