Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 38 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ A Python library for integrating [Payload](https://payload.com).

## Installation

## Install using pip
### Install using pip

```bash
pip install payload-api
Expand Down Expand Up @@ -39,6 +39,27 @@ import payload
pl = payload.Session('secret_key_3bW9JMZtPVDOfFNzwRdfE')
```

### API Versioning

The Payload API supports multiple versions. You can specify which version to use when making requests:

```python
import payload as pl
pl.api_key = 'secret_key_3bW9JMZtPVDOfFNzwRdfE'
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this isn't a real secret key?

pl.api_version = 'v2' # Use API v2
```

Or with sessions:

```python
import payload
pl = payload.Session(
'secret_key_3bW9JMZtPVDOfFNzwRdfE',
api_version='v2'
)
```

API v2 introduces new objects including `Profile`, `Intent`, `Entity`, `Transfer`, `ProcessingAgreement`, and more. See the [Payload API Documentation](https://docs.payload.com) for details on API versions.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will you wait to merge until the docs are live?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we need to get these out so we can expose the docs.


### Creating an Object

Expand All @@ -60,7 +81,9 @@ customer = pl.Customer.create(
payment = pl.Payment.create(
amount=100.0,
payment_method=pl.Card(
card_number='4242 4242 4242 4242'
card_number='4242 4242 4242 4242',
expiry='12/28',
card_code='123'
)
)
```
Expand Down Expand Up @@ -107,12 +130,21 @@ payments = pl.Payment.filter_by(

### Testing the Payload Python Library

Tests are contained within the tests/ directory. To run a test file, once within the
pipenv shell, enter the command in terminal
Tests are contained within the tests/ directory. To run tests:

```bash
TEST_SECRET_KEY=test_api_key pytest tests/{__FILENAME__}.py
```
# Install dependencies
pdm install

# Run integration tests
TEST_SECRET_KEY=test_api_key pdm run pytest tests/int/

# Run unit tests
pdm run pytest tests/unit/

# Run a specific test file
TEST_SECRET_KEY=test_api_key pdm run pytest tests/int/test_transaction.py
```


## Documentation
Expand Down
141 changes: 136 additions & 5 deletions payload/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,151 @@

Documentation: https://docs.payload.com

:copyright: (c) 2021 Payload (http://payload.com)
:copyright: (c) 2026 Payload (http://payload.com)
:license: MIT License
"""

from .version import __version__
from .exceptions import *
from .objects import *
from .arm import Attr as attr, ARMRequest, session_factory
__all__ = [
# Version
'__version__',
# ARM
'ARMRequest',
'attr',
'session_factory',
'Session',
# Functions
'create',
'update',
'delete',
# Module variables
'URL',
'api_key',
'api_url',
'api_version',
# Submodules
'objects',
# Exceptions
'BadRequest',
'Forbidden',
'InternalServerError',
'InvalidAttributes',
'NotFound',
'PayloadError',
'ServiceUnavailable',
'TooManyRequests',
'TransactionDeclined',
'Unauthorized',
'UnknownResponse',
# Objects
'AccessToken',
'Account',
'BankAccount',
'BillingCharge',
'BillingSchedule',
'Card',
'ChargeItem',
'ClientToken',
'Credit',
'Customer',
'Deposit',
'Invoice',
'Ledger',
'LineItem',
'OAuthToken',
'Org',
'Payment',
'PaymentActivation',
'PaymentItem',
'PaymentLink',
'PaymentMethod',
'ProcessingAccount',
'ProcessingRule',
'Refund',
'Transaction',
'User',
'Webhook',
# New API v2 Objects
'Profile',
'BillingItem',
'Intent',
'InvoiceItem',
'PaymentAllocation',
'Entity',
'Stakeholder',
'ProcessingAgreement',
'Transfer',
'TransactionOperation',
'CheckFront',
'CheckBack',
'ProcessingSettings',
]

from . import objects
from .arm import ARMRequest
from .arm import Attr as attr
from .arm import session_factory
from .exceptions import (
BadRequest,
Forbidden,
InternalServerError,
InvalidAttributes,
NotFound,
PayloadError,
ServiceUnavailable,
TooManyRequests,
TransactionDeclined,
Unauthorized,
UnknownResponse,
)
from .objects import ( # API v2 Objects
AccessToken,
Account,
BankAccount,
BillingCharge,
BillingItem,
BillingSchedule,
Card,
ChargeItem,
CheckBack,
CheckFront,
ClientToken,
Credit,
Customer,
Deposit,
Entity,
Intent,
Invoice,
InvoiceItem,
Ledger,
LineItem,
OAuthToken,
Org,
Payment,
PaymentActivation,
PaymentAllocation,
PaymentItem,
PaymentLink,
PaymentMethod,
ProcessingAccount,
ProcessingAgreement,
ProcessingRule,
ProcessingSettings,
Profile,
Refund,
Stakeholder,
Transaction,
TransactionOperation,
Transfer,
User,
Webhook,
)
from .version import __version__
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you have to adjust all of these imports?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we don't use * imports which is considered bad practice.


URL = 'https://api.payload.com'

api_key = None
api_url = URL
api_version = None

Session = session_factory('PayloadSession', objects)

Expand Down
4 changes: 4 additions & 0 deletions payload/arm/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ def _request(self, method, id=None, headers=None, params=None, json=None):
auth = (session.api_key, '')
files = {}

if session.api_version:
headers['X-API-Version'] = session.api_version

if json:
flat_data = nested_qstring_keys(copy.copy(json))
for k in list(flat_data):
Expand Down Expand Up @@ -63,6 +66,7 @@ def _request(self, method, id=None, headers=None, params=None, json=None):
auth=auth,
data=flat_data,
files=files,
headers=headers,
)
else:
response = getattr(requests, method)(
Expand Down
15 changes: 9 additions & 6 deletions payload/arm/session.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
from .request import ARMRequest
from .object import ARMObject, ARMObjectWrapper
from . import Attr
import types
import inspect
import payload

from . import Attr
from .object import ARMObjectWrapper
from .request import ARMRequest


def get_object(objects, name):
if isinstance(objects, dict):
return objects[name]
else:
return getattr(objects, name)


class Session(object):
attr = Attr

def __init__(self, api_key=None, api_url=None):
def __init__(self, api_key=None, api_url=None, api_version=None):
self.api_key = api_key or payload.api_key
self.api_url = api_url or payload.api_url
self.api_version = api_version or payload.api_version

def create(self, *args, **kwargs):
return ARMRequest(session=self).create(*args, **kwargs)
Expand All @@ -30,5 +32,6 @@ def delete(self, *args, **kwargs):
def __getattr__(self, name):
return ARMObjectWrapper(get_object(self._objects, name), self)


def session_factory(name, objects):
return type(name, (Session,), {'_objects': objects})
Loading