Giter Club home page Giter Club logo

braintree-go's Introduction

Braintree Go

GoDoc Build Status Go Report Card

A Go client library for Braintree, the payments company behind awesome companies like GitHub, Heroku, and 37signals.

This is not an official client library. Braintree maintains server-side libraries for Ruby, Python, PHP, Perl, Node, C# and Java, but not Go. This package implements the core functionality of the other client libraries, but it's missing a few advanced features.

With that said, this package contains more than enough to get you started accepting payments using Braintree. If there's a feature the other client libraries implement that you really need, open an issue (or better yet, a pull request).

Usage

Setting up your credentials is easy.

import "github.com/braintree-go/braintree-go"

bt := braintree.New(
  braintree.Sandbox,
  "YOUR_BRAINTREE_MERCH_ID",
  "YOUR_BRAINTREE_PUB_KEY",
  "YOUR_BRAINTREE_PRIV_KEY",
)

So is creating your first transaction.

ctx := context.Background()
tx, err := bt.Transaction().Create(ctx, &braintree.TransactionRequest{
  Type: "sale",
  Amount: braintree.NewDecimal(100, 2), // 100 cents
  CreditCard: &braintree.CreditCard{
    Number:         "4111111111111111",
    ExpirationDate: "05/14",
  },
})

The error returned by these calls is typed. The package returns a generic error when something mechanical goes wrong, such as receiving malformed XML or being unable to connect to the Braintree gateway. However, if Braintree was able to process the request correctly, but was unable to fulfill it due to a semantic failure (such as the credit card being declined) then a BraintreeError type is returned.

In addition to creating transactions, you can also tokenize credit card information for repeat or subscription billing using the CreditCard, Customer, and Subscription types. This package is completely compatible with Braintree.js, so if you encrypt your customers' credit cards in the browser, you can pass them on to Braintree without ever seeing them yourself. This decreases your PCI regulatory exposure and helps to secure your users' data. See the examples folder for a working implementation.

Installation

The usual. go get github.com/braintree-go/braintree-go

Supported Go Versions

  • 1.7
  • 1.8
  • 1.9
  • 1.10
  • 1.11
  • 1.12

Documentation

Braintree provides a ton of documentation on how to use their API. I recommend you use the Ruby documentation when following along, as the Ruby client library is broadly similar to this one.

For details on this package, see GoDoc.

Testing

The integration tests run against a sandbox account created in the Braintree Sandbox. See TESTING.md for further instructions on how to set up your sandbox for integration testing.

You can run tests locally using the same credentials that Travis CI uses by using the credentials in .default.env. Simply cp .default.env .env if you use a tool that autoloads .env files, or source .default.env to load the credentials into your shell. Then run tests with go test -tags='unit integration' ./....

source .default.env
go test -tags='unit integration' ./...

Webhook Integration Testing

You can use the WebhookTestingGateway to write your own integration tests to verify your application is processing incoming webhook notifications correctly.

A simple example:

package integration_test

import (
  "testing"
  "net/http/httptest"

  "github.com/braintree-go/braintree-go"
)

func TestMyWebhook(t *testing.T) {
  bt := braintree.New(
    braintree.Sandbox,
    "merchaint_id",
    "public_key",
    "private_key",
  )

  r, err := bt.WebhookTesting().Request(
    braintree.SubscriptionChargedSuccessfullyWebhook,
    "123", // id
  )
  if err != nil {
    t.Fatal(err)
  }

  // You can now send the payload and signature to your webhook handler
  // and test your application's busines logic

  w := httptest.NewRecorder()
  router.ServeHTTP(w, r)

  // assertions
}

License

The MIT License (MIT)

Copyright (c) 2013 Lionel Barrow

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Contributors

braintree-go's People

Contributors

alasdairf avatar bastiankoetsier avatar braintreeps avatar brmasson avatar ccahoon avatar codewitch avatar dbudworth avatar dsmcfarl avatar ducnt114 avatar emdotcarter avatar fabriziomoscon avatar jszwedko avatar juliendsv avatar jvalecillos avatar kayleg avatar kjperry avatar leighmcculloch avatar lionelbarrow avatar lquach avatar michaljemala avatar pranavraja avatar richardknop avatar rkulla avatar seklfreak avatar shugyousha avatar tamalsaha avatar tengis617 avatar ulisesflynn avatar vania-pooh avatar vially avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  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  avatar  avatar  avatar  avatar  avatar  avatar

braintree-go's Issues

number_of_billing_cycles missing in Modification

the Modification structure is missing the number_of_billing_cycles field, which makes it impossible to get the default number of cycles of a discount/add-on ID, or the number of cycles of a discount/add-on within a subscription

Escrow support

Hello!

I'm just getting started with Braintree for my application, and it's really awesome to see this library that supports Golang for Braintree. However, I need escrow support for my application.

Is there anyone working on this?

404 Error ?

Hey, I just got a 404 error here does that mean braintree may have changed it's API and this is now pointing to the wrong place ?

MarshalText panics

I am using the following code to create a subscription:

return s.Client.Subscription().Create(&braintree.Subscription{
    PlanId:             sub.PlanID,
    PaymentMethodToken: cc.Token,
})

Then I Marshal first return value and send to a browser, but have a panic:

 runtime error: slice bounds out of range
...
userspace/vendor/github.com/lionelbarrow/braintree-go.(*Decimal).MarshalText(0xc42043c8a0, 0x7c7b20, 0xc42043c8a0, 0xc42034d388, 0xc42043c8a0, 0xc4200a4b00)
/go/src/userspace/vendor/github.com/lionelbarrow/braintree-go/decimal.go:31 +0x202

Advanced search

Hey @eaigner, would you find the advanced search functionality described here or here useful? I was thinking of taking a crack at it this weekend.

Oauth gateway for partners API

Hi,

I would love to see support for the oauth gateway to enable using the partners API.

The documentation from braintree is here, and I believe the ruby equivalent is here.

Has anyone started working on it? Is anyone else interested?

Make newHmacer Exported

Correct me if I am wrong but if I want to create an API endpoint in Golang to parse Braintree webhooks, I will need to build HMAC signature in order to parse the webhook data.

So I would need to do something alongside these lines:

package api

import (
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
)

// BraintreeWebhook - GET /api/v1/braintree-webhook/
func BraintreeWebhook(w http.ResponseWriter, r *http.Request) {
	// Request body cannot be nil
	if r.Body == nil {
		http.Error(w, "Request body cannot be nil", http.StatusBadRequest)
		return
	}

	// Read the request body
	payload, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, "Error reading request body", http.StatusBadRequest)
		return
	}

	webhookGateway := testGateway.WebhookNotification()
	hmacer := newHmacer("my_public_key", "my_private_key")

	hmacedPayload, err := hmacer.hmac(base64.StdEncoding.EncodeToString(payload))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	signature := fmt.Sprintf("%s|%s", hmacer.publicKey, hmacedPayload)

	notification, err := webhookGateway.Parse(signature, payload)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	log.Print("Printing parsed notification: ")
	log.Printf("%v", notification)

	// business logic ...

	w.WriteHeader(http.StatusOK)
	fmt.Fprint(w, "Notification accepted")
}

The problem is the newHmacer function is not exported.

It would be to export this functionality so it can be imported by projects as currently I have to copy paste it.

Device data support

Hi, I love the project and am trying to use full Go for a new site. According to this, it is recommended to provide device data when using a Vault record initiate a transaction. I do not see any way to provide this data using the Go lib. I have already collected the device data, just need a way to provide it to Braintree.

Thanks,
Rob

Discounts and add-ons

I have a branch adding support for subscription discounts and add-ons, so that'll be coming soon.

Web Notification Error

I keep getting a 'Signature-key pair contains more than one |' error when i try to parse a notification.

The signature i got from Braintree has 2 '|'. Am I missing something? Am i suppose to do something before passing the signature or payload?

Open REST Api

Do you have documentation on the brain tree rest API. I read an article where they stated they only want to expose client API's and I would like to contribute to this one however without any documentation I am flying blind.

Unable to distinguish between network errors and api errors?

I'm trying determine the failure reason of bt.Customer().Find(customerID).

It returns an error (but not of any exported type) so I can't seem to distinguish between network errors, and the customer not actually existing.

The README states "If Braintree was able to process the request correctly, but was unable to fulfill it due to a semantic failure (such as the credit card being declined) then a BraintreeError type is returned.". The problem is that BraintreeError doesn't seem to be defined anywhere (just an unexported braintreeError), and it's not used for customer find anyways.

Please help me to shed some light on this. Thank you!

Google App Engine failure

Trying to use the library from within Google App Engine yields a failure:

Fatal errorPost https://sandbox.braintreegateway.com/merchants/XXX/customers: http.DefaultTransport and http.DefaultClient are not available in App Engine. See https://cloud.google.com/appengine/docs/go/urlfetch/

It looks like using those calls are considered bad (same issue fixed in the OAuth library golang/oauth2#27 ).

Are you able to pitch a fix for that particular issue? I can help with testing if need be

Is there any PayPal example?

I want to pay with paypal, but I can't find entrance to put my merchantAccountId when I generate the token.
So I try to create transcation or subcription with nonce and put my merchantAccountId in the transcationRequest or subcriptionRequest. It told me that Payment instrument type is not accepted by this merchant account.

PS: I try it in sandbox env

Paginated Search

While using braintree-go at Daily Burn a while back, we noticed that the transaction search would only return the first 50 results or so, so we added paginated search results to the library.

Haven't been able to find the time to clean up our code and submit a proper PR but here is an example of what we did if someone wants to use as a reference to implement this if there's no existing way to do it https://github.com/dailyburn/braintree-go/commit/d44aa131caad6055c0e4aac2f3a24450aa818c63

Sample Webhook notification

Hello,
Is there a way to generate a sample webhook notification like in other drivers ?
I can work on a PR if needed.
Thanks

How do you apply a discount?

I've tried many variations but whatever I do it doesn't seem like I can apply a discount to a new subscription (the []interface{} type of Subscription's Discounts field isn't very helpful in this regard either).

The returned error is Forbidden (403) in all cases.

Use a "nullable" type for primitive values that may be empty in Braintree responses

E.g. Plan.NumberOfBillingCycles may be empty in the response XML from Braintree, but is otherwise an integer. We currently deserialize to a string to avoid this issue.

Possible solutions:

  • Create types that can either be an int (or bool, float, etc.) or nil and use those (similar to sql.NullInt)
  • Make use of https://github.com/guregu/null which does this work, but would require us to introduce a third-party dependency and expose that dependency to the end user

Bump api version?

I noticed that the official Ruby sdk is using Api version 4 of braintree, but Braintree-go is still on version 3.

I'm not sure of what the differences are, and 3 still seems to work fine, but it's perhaps worth looking into by someone who knows.

Adding payment Methods for a Customer from Nonce

I am trying to use your library for developing an application. On that i am using drop-in UI. that sends payment_method_nonce. I can manage successful transaction using this, But the problem is i can not use this while subscribing a plan. I have customer info coming from another source. So when adding customer i do not have any credit card information. So i need to add payment Method from nonce when user submits the drop-in ui forms.

On Php
On Java

Is there anything for this go lib? if not do you have it in mind to implement in near future?

Thanks for writing this library.

Runnung the tests

I did not find out how to create a transaction with the id 'dskdmb' to run the tests successfully.

Credit card token field is not set after transaction

Hi,

Thank you for building this go package for braintree.
I may have found a possible issue that I want to bring to your attention.

When I run the code mentioned below, the transaction got approved but the tx.CreditCard.Token (tokenized credit card number) field is not set. Can anyone fix this please?

    bt := braintree.New(
	braintree.Sandbox,
	"47sdtstnwjp8xy7k",
	"nxf5g2kx2wgdtrrs",
	"********************************",
)

ctx := context.Background()
tx, err := bt.Transaction().Create(ctx, &braintree.TransactionRequest{
	Type: "sale",
	Amount: braintree.NewDecimal(100, 2), // 100 cents
	CreditCard: &braintree.CreditCard{
		Number:         "4111111111111111",
		ExpirationDate: "05/14",
	},
}) 

secure way to use contexts?

I am curious how to use contexts with this library in a secure way.

Let's use this example:

ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()

customer, err := api.Customer().Find(ctx, "customerID")

// do some other work that might take some time

pm, err := api.PaymentMethod().Create(ctx, &braintree.PaymentMethodRequest{
    CustomerId:         customer.Id,
    PaymentMethodNonce: "nonce",
})

If the context get canceled during the PaymentMethod().Create() we can get into a state where we think the api call failed, but it actually was successful.

You could argue to just increase the timeout of the cancel to 2 minutes, but even this would be insecure because of the additional time spend between the 2 calls to braintree.

Even if you only use context without timeouts you need to make sure to never cancel those in the first 60s of a braintree api call.

I didn't find an easy way to use contexts in a secure way.

Field-specific error messages

When Braintree is sent invalid input, it returns an error object that contains both a global summary of what went wrong and field-specific error messages. For example in the Ruby client library:

result = Braintree::Customer.create(
  :credit_card => {
    :number => "bacd123",
    :billing_address => {
      :country_name => "mars"
    }
  }
)

You can then do both this (which is what the Go library currently supports):

result.message
>>>> "some error message"

and this:

result.errors.for(:credit_card).for(:number)
>>>> "credit card number must be numeric"
result.errors.for(:credit_card).for(:billing_address).for(:country_name)
>>>> "mars is not a country"

This allows for people to be more specific when displaying errors to their user. I'll investigate possible ways for us to support this.

Refunds

Hi, I'm trying to add refunds. When trying to test, it seems that I need to do a PUT to /transactions//settle in order to settle a transaction, before refunding it. For some reason this returns 404, can you please advice how it can be done?

Thanks,
Kiril

support context.Context in all remote APIs

Passing contexts around for timeouts, cancellation, and other behaviors is now common and well-documented in Go land. It'd be really nice to have support for that in braintree-go. Even Context versions of the methods like how database/sql was updated would work.

Customer update with VerifyCard: false returns "Gateway Rejected: cvv"

Hi, I've been using braintree-go and I've come into an issue where I'm trying to update a customer's credit card billing address without using a payment method nonce, and I'm getting the "Gateway Rejected: cvv" error response.

I have the VerifyCard field set to false in CreditCardOptions, which I believe should help me avoid getting this error response.

Anyways, my code is at the bottom. Let me know if anyone else has seen this same issue or if I'm doing anything incorrectly.

c, err := s.api.Customer().Update(
	&braintree.Customer{
		Id: req.UserToken,
		CreditCard: &braintree.CreditCard{
			Options: &braintree.CreditCardOptions{
				UpdateExistingToken: req.PaymentMethodToken,
				VerifyCard:          false,
			},
			CardholderName: req.CardholderName,
			BillingAddress: &braintree.Address{
				StreetAddress:     req.BillingAddress.StreetAddress,
				ExtendedAddress:   req.BillingAddress.ExtendedAddress,
				PostalCode:        req.BillingAddress.PostalCode,
				CountryCodeAlpha2: req.BillingAddress.CountryCodeAlpha2,
			},
		},
	},
)

Tokenization of Credit Card without making a sale

Hi,

I'm building a software that tokenizes credit card numbers using your Go package and would very much appreciate if you guys can add this following functionality.

I want to get a token (Credit card number that is tokenized) from Braintree without making a sale (i.e) I want Braintree to give me a token back without charging the credit card.

Thanks,

401 Unauthorised when trying form example

I'm using your example server.go with form.html and when I feed it my values it gives back an Unauthorised 401 - known issue?

Have I missed a step? I ran go run server.go and hit it at localhost with a demo credit card of:
"4111111111111111"
"05/2010"
"100"

which should succeed. I even hardcoded my merch details into the app for testing and still unauthorised.

Specify default http.Client timeout

Hey,

While right now we can use NewWithHttpClient to pass in our own HTTP client, would it make sense to choose a sensible default for the Timeout field instead of using net/http's default client (which has no timeout)?

I went through our codebase after reading this post, so just dropping notes where I can.

Thanks for the renewed attention for this package by the way. Using it in production and it's been great! Any chance Braintree will "officially" support this one?

Refund Capability

Hi there,

I've looked and there doesn't seem to be a Refund capability for settled transactions at the moment. Could you confirm this?

If so, can I put it as a function of TransactionGateway in a pull request? It looks like it should be a POST to "/transactions/#{transaction_id}/refund" with params: transaction => {:amount => amount})

Thanks!
Thomas

Production ready?

Hi, I'm looking at using Go to talk to Braintree and found this library. I'm wondering if it's been used in anything serious and whether it will continue to be maintained?

Thanks.

Add a CHANGELOG before next version

We should add a CHANGELOG to the project that outlines significant changes and new features between releases. As this package is still pre-v1 there may be small breaking changes in the exported api and this will be one place we can also highlight them between pre-v1 versions, and between major versions when we have them.

Suggested by @jszwedko in comments on #120.

RiskData

Hi,

Moving some processing from PHP to Go.

I'll provide some context...

I'm using RiskData per here: https://developers.braintreepayments.com/reference/response/transaction/php#risk_data

Which is something like:

$result = Braintree_Transaction::sale([
	...
    'riskData' => Array(
		'customerIp' => $this->ci->input->ip_address(),
		'customerBrowser' => substr($_SERVER['HTTP_USER_AGENT'], 0, 254) // 255 Characters Max
	)
]);

I've seen that the Transaction struct contains DeviceData, so that's customerBrowser sorted.

Where would I be able to submit the IP?

Thanks

Transaction Currency

We need to use other currencies other than Euro on our system. There seems to be no support for currencies on Transactions implemented, so we added:

CurrencyIsoCode string xml:"currency-iso-code,omitempty"``

to transaction.go

Yet, when we try to process a transaction:

tx, err := bt.Transaction().Create(&braintree.Transaction{
  Type: "sale",
  CurrencyIsoCode: string(b.Currency),
  Amount: braintree.NewDecimal(int64(b.Total*100), 2),
  PaymentMethodToken: cc.Token,
})

we get on the response the error:

Forbidden (403)

Does it have to do with the implementation or the account definition ?

AVS/CVV/Gateway/Tax Amount/Tax Exempt Transaction Fields

Hello! Thanks for the great library. It's exciting to see so much great work being done on it!

I've got a branch based on a fairly old revision that implements a couple more transaction fields (and some alternative implementations of great work you've done since then). I haven't updated to the latest revision, but in a few months when I do, I'd be able to submit a pull request, but I wanted to ask first—would you prefer a PR at that point, or just a note that I'd use them if you added them?

TLS 1.2 as default

Hey,

given the fact that Braintree will drop TLS support for less than 1.2, would you accept a PR that sets this as the default minimum TLS version to be used by the actual HTTP client?

Forbidden (403) when using nonce token

Hello Lionel,

Great work with the library. I'm trying to create a Transaction with the PaymentMethodNonce property instead of using a direct Credit Card payment but keep hitting a 403. This nonce value is retrieved after my server returns a client token and the client tokenizes their payment through paypal. Here's roughly how the process looks like:

bt = braintree.New(braintree.Production, merchId, pubKey, privKey)

Client asks for a client token:
token, err := bt.ClientToken().Generate()
//return this token to client

//paypalInstance now uses this token to tokenize a nonce payload and then I send this to my server. I then process this nonce into a Transaction:

nonce := r.URL.Query.get("nonce")
tx, err := bt.Transaction().Create(&braintree.Transaction{
Type: "sale",
Amount: amount,
PaymentMethodNonce: nonce,
MerchantAccountId: "USD",
})

if err != nil {
logger.Debugf("Failed to create transaction: %v", err)
http.Error(w, "", http.StatusInternalServerError)
return
}

I've checked with braintree and paypal payment method is enabled so I'm not sure if this is the correct implementation for nonce payments.

Running integration tests ...

Possible dumb question: How do I create a transaction in the Braintree sandbox with a specific Transaction ID? I don't see a way through the web-console interface or the API to create a transaction with a specific ID.

How To Get Signature From Request

Hello,

How can I get signature from *http.Request object in my handler where I want to parse a webhook notification like this:

payload, err := ioutil.ReadAll(r.Body)
if err != nil {
	http.Error(w, "Error reading request body", http.StatusBadRequest)
	return
}

bt.WebhookNotification().Parse(signature, string(payload))

I assume payload is just the content of HTTP POST data but where is signature? In one of the headers?

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.