Coder Social home page Coder Social logo

checkout-sdk-python's Introduction

Checkout.com Python SDK

build-status CodeQL

build-status GitHub release PyPI - latest

GitHub license

Getting started

# Requires Python > 3.6
pip install checkout-sdk==<version>

Version 3.0.0 is here!

We improved the initialization of SDK making it easier to understand the available options.
Now NAS accounts are the default instance for the SDK and ABC structure was moved to a previous prefixes.
If you have been using this SDK before, you may find the following important changes:

  • Imports: if you used to import checkout_sdk.payments.payments now use checkout_sdk.payments.payments_previous
  • Marketplace module was moved to Accounts module, same for classes and references.
  • In most cases, IDE can help you determine from where to import, but if you’re still having issues don't hesitate to open a ticket.

πŸš€ Please check in GitHub releases for all the versions available.

πŸ“– Checkout our official documentation.

πŸ“š Check out our official API documentation guide, where you can also find more usage examples.

How to use the SDK

This SDK can be used with two different pair of API keys provided by Checkout. However, using different API keys imply using specific API features. Please find in the table below the types of keys that can be used within this SDK.

Account System Public Key (example) Secret Key (example)
Default pk_pkhpdtvabcf7hdgpwnbhw7r2uic sk_m73dzypy7cf3gf5d2xr4k7sxo4e
Previous pk_g650ff27-7c42-4ce1-ae90-5691a188ee7b sk_gk3517a8-3z01-45fq-b4bd-4282384b0a64

Note: sandbox keys have a sbox_ or test_ identifier, for Default and Previous accounts respectively.

If you don't have your own API keys, you can sign up for a test account here.

PLEASE NEVER SHARE OR PUBLISH YOUR CHECKOUT CREDENTIALS.

Default

Default keys client instantiation can be done as follows:

from checkout_sdk.checkout_sdk import CheckoutSdk
from checkout_sdk.environment import Environment


def default():
    # public key is optional, only required for operations related with tokens
    checkout_api = CheckoutSdk
        .builder()
        .secret_key('secret_key')
        .public_key('public_key')
        .environment(Environment.sandbox())
        .build()

    payments_client = checkout_api.payments
    payments_client.refund_payment('payment_id')

Default OAuth

The SDK supports client credentials OAuth, when initialized as follows:

from checkout_sdk.checkout_sdk import CheckoutSdk
from checkout_sdk.environment import Environment
from checkout_sdk.oauth_scopes import OAuthScopes


def oauth():
    checkout_api = CheckoutSdk
        .builder()
        .oauth()
        .client_credentials(client_id='client_id', client_secret='client_secret')
        .environment(Environment.sandbox())
        .scopes([OAuthScopes.GATEWAY_PAYMENT_REFUNDS, OAuthScopes.FILES])
        .build()

    payments_client = checkout_api.payments
    payments_client.refund_payment('payment_id')

Previous

If your pair of keys matches the Previous type, this is how the SDK should be used:

from checkout_sdk.checkout_sdk import CheckoutSdk
from checkout_sdk.environment import Environment

def previous():
    # public key is optional, only required for operations related with tokens
    checkout_api = CheckoutSdk
        .builder()
        .previous()
        .secret_key('secret_key')
        .public_key('public_key')
        .environment(Environment.sandbox())
        .build()

    payments_client = checkout_api.payments
    payments_client.refund_payment('payment_id')

Logging

Checkout SDK custom logger can be enabled and configured through Python's logging module:

import logging
logging.basicConfig()
logging.getLogger('checkout').setLevel(logging.INFO)

HttpClient

Checkout SDK uses requests library to perform http operations, and you can provide your own custom http client implementing HttpClientBuilderInterface

import requests
from requests import Session

import checkout_sdk
from checkout_sdk.checkout_sdk import CheckoutSdk
from checkout_sdk.environment import Environment
from checkout_sdk.oauth_scopes import OAuthScopes
from checkout_sdk.http_client_interface import HttpClientBuilderInterface


class CustomHttpClientBuilder(HttpClientBuilderInterface):

    def get_client(self) -> Session:
        session = requests.Session()
        session.max_redirects = 5
        return session


def oauth():
    checkout_api = CheckoutSdk
        .builder()
        .oauth()
        .client_credentials(client_id='client_id', client_secret='client_secret')
        .environment(Environment.sandbox())
        .http_client_builder(CustomHttpClientBuilder())
        .scopes([OAuthScopes.GATEWAY_PAYMENT_REFUNDS, OAuthScopes.FILES])
        .build()

    payments_client = checkout_api.payments
    payments_client.refund_payment('payment_id')

Exception handling

All the API responses that do not fall in the 2** status codes will cause a CheckoutApiException. The exception encapsulates the http_metadata and a dictionary of error_details, if available.

try:
    checkout_api.customers.get("customer_id")
except CheckoutApiException as err:
    http_status_code = err.http_metadata.status_code
    error_details = err.error_details

Building from source

Once you checkout the code from GitHub, the project can be built using pip:

# install the latest version pip
python -m pip install --upgrade pip

# install project dependencies
pip install -r requirements-dev.txt

# run unit and integration tests
python -m pytest

The execution of integration tests require the following environment variables set in your system:

  • For Default account systems: CHECKOUT_DEFAULT_PUBLIC_KEY & CHECKOUT_DEFAULT_SECRET_KEY
  • For OAuth account systems: CHECKOUT_DEFAULT_OAUTH_CLIENT_ID & CHECKOUT_DEFAULT_OAUTH_CLIENT_SECRET
  • For Previous account systems: CHECKOUT_PREVIOUS_PUBLIC_KEY & CHECKOUT_PREVIOUS_SECRET_KEY

Code of Conduct

Please refer to Code of Conduct

Licensing

MIT

checkout-sdk-python's People

Contributors

a-ibarra avatar armando-rodriguez-cko avatar armandojaleo avatar cko-developer-portal[bot] avatar delenamalan avatar martinseco avatar match-cheng avatar natim avatar nicolas-maalouf-cko avatar renaldy-widjaja-cko avatar riaz-bordie-cko avatar riazb avatar rsaestrela avatar yusufosman avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

checkout-sdk-python's Issues

Add serializer to response wrapper

Environment

  • Checkout SDK version: latest

Description

A serializer can be useful, when the response fully or partially

  • need to be stored in a database in a JSON serialized form
  • need to be parsed using pydantic or similar parser
  • may be easier to handle that way.

Proposed Solution

  • I may be able to implement this feature.

Master Card - Unprocessible entity

Environment

  • Checkout SDK version: 3.0.12
  • Platform and version:
  • Operating System and version:

Description

While using test master card numbers, I'm getting error with status 422
my code:
def request_donation_payment(data):
token = data.get('token')
amount = data.get('donation_amount')
payment_reference = 'enwwf-donation'
payment_description = 'Emirates Nature - WWF Donation Payment'
phone_number = data.get('phone')
first_name = data.get('first_name')
last_name = data.get('last_name')
email = data.get('email')
customer_name = first_name+' '+last_name
language = data.get('language')

# API Keys

api = CheckoutSdk.builder() \
    .secret_key(SECRET_KEY) \
    .public_key(PUBLIC_KEY) \
    .environment(ENVIRONMENT) \
    .build()

phone = Phone()
phone.number = phone_number

request_token_source = PaymentRequestTokenSource()
request_token_source.token = token

customer_request = CustomerRequest()
customer_request.email = email
customer_request.name = customer_name

payment_individual_sender = PaymentInstrumentSender()

three_ds_request = ThreeDsRequest()
three_ds_request.enabled = True

request = PaymentRequest()
request.source = request_token_source
request.capture = False
request.reference = payment_reference
request.description = payment_description
request.amount = amount*100
request.currency = Currency.AED
request.customer = customer_request
request.sender = payment_individual_sender
request.processing_channel_id = settings.CKO_PROCESSING_CHANNEL_ID
request.three_ds = three_ds_request
if language == 'ar':
    request.success_url = settings.DONATION_APP_URL+'/ar/loading'
    request.failure_url = settings.DONATION_APP_URL+'/ar/loading'
else:
    request.success_url = settings.DONATION_APP_URL+'/loading'
    request.failure_url = settings.DONATION_APP_URL+'/loading'

logger = logging.getLogger(__name__)

try:
    response = api.payments.request_payment(request)
    payment_request_data = {
        'amount': amount,
        'status_code': response.http_metadata.status_code,
        'reference': response.reference,
    }
    logger.info(json.dumps(["PAYMENT_LOG", payment_request_data]))
    return response

except CheckoutApiException as err:
    logger.error("Donation Payment Error")
    error_details = err.error_details
    http_status_code = err.http_metadata.status_code if err.http_metadata else None

    logger.error('ERROR CODE: %s', http_status_code)
    logger.error('ERROR LIST: %s', json.dumps(error_details))
    return err

response comes as attachment.

Proposed Solution

  • I may be able to implement this feature
    Screenshot 2023-08-01 at 4 19 31 PM

Cannot import checkout_sdk with the latest version (3.0.19)

Environment

  • Checkout SDK version: 3.0.19
  • Platform and version: Any
  • Operating System and version: Any

Description

Importing checkout_sdk results in an error with version 3.0.19.

Current behavior

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/tmp/checkout/lib/python3.11/site-packages/checkout_sdk/__init__.py", line 3, in <module>
    from checkout_sdk.checkout_sdk import CheckoutSdk # noqa
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/checkout/lib/python3.11/site-packages/checkout_sdk/checkout_sdk.py", line 3, in <module>
    from checkout_sdk.default_sdk import DefaultSdk
  File "/tmp/checkout/lib/python3.11/site-packages/checkout_sdk/default_sdk.py", line 5, in <module>
    from checkout_sdk.checkout_api import CheckoutApi
  File "/tmp/checkout/lib/python3.11/site-packages/checkout_sdk/checkout_api.py", line 15, in <module>
    from checkout_sdk.payments.sessions.sessions_client import PaymentSessionsClient
ModuleNotFoundError: No module named 'checkout_sdk.payments.sessions'

Steps to reproduce

$ pip install checkout-sdk==3.0.19
$ python -c 'import checkout_sdk'

Possible solution

Probably introduced by #148.
I think that a __init__.py file is missing in checkout_sdk/payments/sessions.

[QUESTION] Why classes have no __init__ methods?

Hi,

I just started implementing updated SDK version and i wonder why none of requests related classes (for example: PaymentRequest, RefundRequest) or related objects (for example: CustomerRequest, ThreeDsRequest) has no init methods? Is it conceptional or you don't mind if i add it?

Btw who i should contact to contribute? :)

Regards,
Michael

Documentation around making a payment is incorrect

The documentation in the README.md has some useful, specific examples about how to request a payment. However, having tried to request a payment using the Source Type: token example it appears that the documentation does not match the code.

The example given is:

    payment = api.payments.request(
        source={
            'token': 'tok_...'.
            'billing_address': { ... },
            'phone': { ... }
        },
        amount=100,                                     # cents
        currency=sdk.Currency.USD,                      # or 'usd'
        reference='pay_ref'
    )
    print(payment.id)

However, this gives a ValueError because the underlying code cannot determine the request type - ValueError: Payment source missing. Please specify a valid card or token..

Having looked through the code I determined that the token field should be a top level item, alongside source. This fixed the immediate problem, but then raised another in that validation was expecting a customer attribute as well, which contained either the email address, or customer ID. This is also undocumented.

Incorrectly typed exception

The CheckoutApiException has incorrectly defined types

Description

The CheckoutApiException is defined as having error_details as a dict when we can see in the __init__ method that self.error_details can be set to None. Thus error_details is actually Optional[dict].

However, in some cases error_details may not be set when response.text is null or missing. An example of such case is when the API responds with a 403 on a payout, error_details is not an available attribute on this exception. Which also means the python examples in the documentation isn't complete for this case and raises an AttributeError on 403.

image

Lastly error_details should actually be a list instead of a dict according to the API documentation, as you can see in the image provided the API mentions that error_codes is an array

image

Additional information

A final point, it would be worthwhile introducing some clear data structures to this library as most of the structs have to be guessed by reading the attributes in the tests. This would be far more helpful than trying to figure out the struct from a nested ResponseWrapper object.

Credentials

Where to get this keys? Which steps i should go to find them? Cant found them at all

For Default account systems: CHECKOUT_PUBLIC_KEY & CHECKOUT_SECRET_KEY
For Four account systems: CHECKOUT_FOUR_PUBLIC_KEY & CHECKOUT_FOUR_SECRET_KEY
For Four account systems (OAuth): CHECKOUT_FOUR_OAUTH_CLIENT_ID & CHECKOUT_FOUR_OAUTH_CLIENT_SECRET

Feature request: initialize InstrumentsClient with API

Is there any particular reason not to initialize the InstrumentsClient with the Checkout API?

From https://github.com/checkout/checkout-sdk-python/blob/unified-payments/checkout_sdk/checkout_api.py#L7

class CheckoutApi:
    def __init__(self, **kwargs):
        config = Config(**kwargs)
        http_client = HTTPClient(config)
        if(config.secret_key is not None):
            self.payments = PaymentsClient(http_client)
        if(config.public_key is not None):
            self.tokens = TokensClient(http_client)

Would be nice to have something like:

from checkout_sdk.vaults import InstrumentsClient, TokensClient

class CheckoutApi:
    def __init__(self, **kwargs):
        ...
        if(config.public_key is not None):
            self.instruments = InstrumentsClient(http_client)

This would simplify interacting with the instruments API.

3D Secure flow is not supported by the SDK

When trying to simulate 3D Secure payment requests, the response object is breaking with the below error:

File "/.../checkout_sdk/payments/payment_processed.py", line 8, in init
self._card = Card(api_response.body['card'])
KeyError: 'card'

How to get All reports

How to get?

  1. All payments ALL details
  2. All Payouts (Transfers) ALL Details
  3. All Disputes ALL details
  4. Each Payments all fees
  5. All Refunds ALL details

Request: custom response classes

ResponseWrapper does not provide contextual hints on what fields it has.

Screen Shot 2022-06-08 at 3 00 47 PM

I suggest creating custom response classes for each checkout_sdk.client.Client subclass, or even for each operation.

Error handling in the readme

These raised exceptions do not have amessage attribute. Thus the log message in the readme fails with AttributeError.

Also the exception definition doesn't contain an error_code attribute

except sdk.errors.CheckoutSdkError as e:
    print('{0.http_status} {0.error_code} {0.elapsed} {0.event_id} // {0.message}'.format(e))

https://github.com/checkout/checkout-sdk-python#payment-request-example-with-n3d-downgrade-option

Also 'error_codes' seems like a valuable attribute to have on the error logging e.g: ['customer_id_invalid', 'destination_token_invalid']

CVV issue

Hello team,

When I've tried payment request by Source Id without CVV on staging/Sandbox environment it's working fine, when I'm trying on the Production environment by Source Id without CVV it's not working and throwing this error "ERROR / INVALID REQUEST PARAMETERS" code "20006", But when I m trying with CVV on Production then it's working fine.

Can somebody confirm, Is CVV is mandatory? or optional

https://github.com/checkout/checkout-sdk-python#source-type-id

{
"source": {
"id":"src_xxxx"
},
"amount": 100,
"currency": "PKR",
"reference": "xx-xx-xxx"
}

Inconsistent error handling

When giving bad card data on purpose while doing a payment request, the exception from CheckoutSdkError is missing values forcing me to run the exception handling this way:

except checkout.errors.CheckoutSdkError as e:
        status_code = e.http_status if e.http_status is not None else 500
        abort(status_code, e.message, error_code=e.error_code)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.