adyen / adyen-go-api-library Goto Github PK
View Code? Open in Web Editor NEWAdyen API Library for Go
License: MIT License
Adyen API Library for Go
License: MIT License
Is your feature request related to a problem? Please describe.
Unable to include idempotency key with payment request using the SDK
Describe the solution you'd like
Implement checkout.Payments
method which takes RequestOptions
similarly to how it is implemented in other SDKs described here.
Describe alternatives you've considered
We can obviously do an HTTP call directly, like it is described here, but that defeats the purpose of the SDK
Describe the bug
This Go library's definition on the fraudResult
field of latest /payments
endpoint is wrong. In fact, each FraudCheckResult
is nested rather than a flat array.
The actual JSON format is:
"fraudResult": {
"accountScore": 90,
"results": [
{
"FraudCheckResult": {
"accountScore": 0,
"checkId": 2,
"name": "CardChunkUsage"
}
},
...
]
}
Current definition in this library:
type FraudResult struct {
// The total fraud score generated by the risk checks.
AccountScore int32 `json:"accountScore"`
// The result of the individual risk checks.
Results *[]FraudCheckResult `json:"results,omitempty"`
}
type FraudCheckResult struct {
// The fraud score generated by the risk check.
AccountScore int32 `json:"accountScore"`
// The ID of the risk check.
CheckId int32 `json:"checkId"`
// The name of the risk check.
Name string `json:"name"`
}
Correct implementation should be:
type FraudResult struct {
// The total fraud score generated by the risk checks.
AccountScore int32 `json:"accountScore"`
// The result of the individual risk checks.
Results *[]FraudCheckResultContainer `json:"results,omitempty"`
}
type FraudCheckResultContainer struct {
FraudCheckResult *FraudCheckResult `json:"FraudCheckResult,omitempty"`
}
type FraudCheckResult struct {
// The fraud score generated by the risk check.
AccountScore int32 `json:"accountScore"`
// The ID of the risk check.
CheckId int32 `json:"checkId"`
// The name of the risk check.
Name string `json:"name"`
}
To Reproduce
To reproduce, make a call to /payments
endpoint (with fraud-related additional data enabled in Adyen CA), and you will find out the elements inside results
array under fraudResult
field in API response could not be unmarshalled correctly.
Expected behavior
Should fix the implementation, the Java library implements it correctly, see https://github.com/Adyen/adyen-java-api-library/blob/develop/src/main/java/com/adyen/model/FraudCheckResultContainer.java
Is your feature request related to a problem? Please describe.
Sorry if I'm missing something, but I haven't found any of the Checkout Modification endpoints in this library. They seem to be implemented for other languages/frameworks (eg: node).
Describe the solution you'd like
A clear path for requesting modifications for "new integrations".
Describe alternatives you've considered
...implementing it myself?
Additional context
N/A.
Is your feature request related to a problem? Please describe.
We use the Result Code as part of the PaymentResult model to check for authorization successes. It would be nice to standardize the acceptable responses into a stronger type, rather than string
Describe the solution you'd like
We could define a new type definition like type AdyenResultCode string
with an enumeration of all values "Refused", "Error", etc and initially just have a function to cast string into this type. Then, maybe on the next major release, we can change the underlying data type to this new type.
Describe alternatives you've considered
Additionally, we could define string constants for the various values so call-sites aren't replicating
with if payment.ResultCode == payments.ResultCodeRefused
but the types would probably be nicer
Additional context
Describe the bug
Hello,
The field merchantAdviceCode is not handled by the Golang SDK. The field doesn’t appear here (or anywhere else in the repository): https://github.com/Adyen/adyen-go-api-library/blob/develop/src/checkout/model_response_additional_data_common.go
But, for example, it exists in your Node.js SDK: https://github.com/Adyen/adyen-node-api-library/blob/ef94f38cc7d887c1d903c10470fbb276188258f8/src/typings/checkout/responseAdditionalDataCommon.ts#L156
The field is documented here: https://docs.adyen.com/api-explorer/#/CheckoutService/v67/post/payments__resParam_additionalData-ResponseAdditionalDataCommon-merchantAdviceCode
Expected behavior
The field merchantAdviceCode to be returned.
Can you add the support for this field please? It's an important one due to the latest rules enforced by Visa and Mastercard leading to a potential extra fee.
SDK
Additional context
The field is available in the Checkout API v67 so it should be straightforward to add it.
At the same time, if other API fields are missing, it could be nice to add them so the SDK can truly match the API.
Update docs.adyen.com to show Go lib code samples as well
The samples needed to be added in Hub for wherever relevant code-sample shortcode is used
Example pages:
https://docs.adyen.com/checkout/get-started
https://docs.adyen.com/checkout/drop-in-web
https://docs.adyen.com/checkout/components-web
https://docs.adyen.com/checkout/api-only
https://docs.adyen.com/checkout/3d-secure/redirect-3ds2-3ds1/web-drop-in
Describe the bug
Library version used: v3.0.0
Payment requests to Adyen using this go library will occasionally result in io.EOF error.
The hypothesis is that, with the http.DefaultClient is used for API requests, the HttpKeepAlive option is enabled, and go will reuse existing connections to send the request.
If the cached connection has been closed by the remote server without notifying, the subsequent request using the connection will result in an EOF error.
To confirm the hypothesis, we create a custom HTTP client (as the code snippet below) and disabled KeepAlives in the transport level and noticed that the EOF error is gone after that, but the request time increased by 0.5s for almost the requests.
If possible, we would like to have it enabled with proper handling of the EOF so that we can avoid the increased request time.
httpclient := &http.Client{}
transportWithDisabledKeepAlive := &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
DisableKeepAlives: true,
}
httpclient.Transport = transportWithDisabledKeepAlive
adyenClient := adyen.NewClient(&adyenCommon.Config{
ApiKey: env.APIKey,
Environment: environment,
LiveEndpointURLPrefix: env.EnvAdyenEndpointPrefix,
HTTPClient: httpclient,
})
To Reproduce
it is a bit difficult to reproduce, one possible way is to continue sending requests in a test loop, and the error should be happening after some time.
Expected behavior
When the EOF error happens, ideally the request should be retried.
If the hypothesis is correct, the request that ends with EOF should never reach the Adyen server, so it should be safe to retry the request in the common/client.go's CallAPI()
method. This needs to be confirmed though.
Describe the bug
MerchantReference is not returned in checkout.PaymentDetailsResponse
after successful payment
To Reproduce
Steps to reproduce the behavior:
details.threeDSResult
from the frontend (the result of the challenge) and you put this in checkout.DetailsRequest
, you get a valid response with ResultCode is Authorised and PSPReference is filled with an ID, but MerchantReference is empty.Expected behavior
In V3 we get MerchantReference back after a successful payment with a creditcard with 3DS2, so we also expect this valiie to be filled in V5.
Additional context
I noticed in Adyen portal that the Payments overview for this payment is reporting the wrong API version: adyen-go-api-library:4.0.0, but I am using 5.0.0. V4 was even more broken, like reported in #93
Is your feature request related to a problem? Please describe.
When receiving platform notifications from Adyen, I can't seem to find models/structs as part of this library to unmarshal the request body into.
Describe the solution you'd like
Ideally, I would like to be able to write something along the lines of:
var notification platform.Notification
if err := json.Unmarshal(reqBody, ¬ification); err != nil {
return err
}
// do something with the notification
Describe alternatives you've considered
I've considered writing the models/structs in-house but I'm already using this library for everything else, so it would be awesome if the library could support this. I'm hoping using the Open-API generator won't be too much work. Happy to collaborate and help out if needed.
Additional context
When calling the /testNotificationConfiguration
route, I receive:
{
"eventDate": "2020-11-24T21:22:25+01:00",
"eventType": "ACCOUNT_HOLDER_CREATED",
"executingUserKey": "ws_285135",
"live": false,
"pspReference": "8816062493452583",
"content": {
"accountCode": "1234567890",
"accountHolderCode": "TestAccountHolder",
"accountHolderDetails": {
"address": {
"city": "Amsterdam",
"country": "NL",
"houseNumberOrName": "6-50",
"postalCode": "1011 DJ",
"stateOrProvince": "Nord Holland",
"street": "Simon Carmiggeltstraat"
},
"bankAccountDetails": [
{
"accountType": "checking",
"bankAccountName": "Primary account",
"bankAccountReference": "Ref#000001",
"bankAccountUUID": "10000000-0000-0000-0000-000000000001",
"bankBicSwift": "BSWFT",
"bankCity": "Amsterdam",
"bankName": "Bank Name Co",
"countryCode": "NL",
"currencyCode": "EUR",
"iban": "NL00NONE1234123412",
"ownerCity": "Amsterdam",
"ownerCountryCode": "NL",
"ownerHouseNumberOrName": "32\/B",
"ownerPostalCode": "1000AA",
"ownerState": "Nord Holland",
"ownerStreet": "Primary Street",
"primaryAccount": true
},
{
"accountNumber": "300000000",
"accountType": "checking",
"bankAccountName": "Secondary account",
"bankAccountReference": "Ref#000002",
"bankAccountUUID": "20000000-0000-0000-0000-000000000002",
"bankBicSwift": "BSWFT",
"bankCity": "Amsterdam",
"bankCode": "10000000",
"bankName": "Other Bank Name",
"branchCode": "20000000",
"countryCode": "NL",
"currencyCode": "GBP",
"ownerCity": "Amsterdam",
"ownerCountryCode": "NL",
"ownerHouseNumberOrName": "12\/B",
"ownerPostalCode": "1000AB",
"ownerState": "Nord Holland",
"ownerStreet": "Secondary Street",
"primaryAccount": false
}
],
"bankAggregatorDataReference": "9876543212",
"businessDetails": {
"doingBusinessAs": "Submerchant Business Name",
"legalBusinessName": "Submerchant Co",
"registrationNumber": "R123456",
"shareholders": [
{
"address": {
"city": "Amsterdam",
"country": "NL",
"houseNumberOrName": "11\/A",
"postalCode": "9999 AA",
"stateOrProvince": "Nord Holland",
"street": "Fake Street"
},
"email": "[email protected]",
"name": {
"firstName": "TestFirstNameOne",
"gender": "FEMALE",
"infix": "van",
"lastName": "TestLastNameOne"
},
"personalData": {
"dateOfBirth": "1981-02-27",
"documentData": [
{
"expirationDate": "2078-02-17",
"issuerCountry": "GB",
"issuerState": "Wales",
"number": "PP1234567",
"type": "PASSPORT"
},
{
"expirationDate": "2081-10-27",
"issuerCountry": "NL",
"issuerState": "Nord Holland",
"number": "ID1234567",
"type": "ID"
}
],
"nationality": "Dutch"
},
"phoneNumber": {
"phoneCountryCode": "NL",
"phoneNumber": "858888138#1111",
"phoneType": "Landline"
},
"shareholderCode": "10000000-0000-0000-0000-000000000001",
"shareholderReference": "SHREF01"
},
{
"address": {
"city": "London",
"country": "GB",
"houseNumberOrName": "22\/B",
"postalCode": "W1A 0AX",
"stateOrProvince": "England",
"street": "Fake Street"
},
"email": "[email protected]",
"name": {
"firstName": "TestFirstNameTow",
"gender": "MALE",
"infix": "van",
"lastName": "TestLastNameTwo"
},
"personalData": {
"dateOfBirth": "1982-03-27",
"documentData": [
{
"expirationDate": "2079-03-17",
"issuerCountry": "GB",
"issuerState": "England",
"number": "DL1234567",
"type": "DRIVINGLICENSE"
},
{
"expirationDate": "2082-11-27",
"issuerCountry": "NL",
"issuerState": "Nord Holland",
"number": "VN1234567",
"type": "VISA"
}
],
"nationality": "British"
},
"phoneNumber": {
"phoneCountryCode": "NL",
"phoneNumber": "858888138#2222",
"phoneType": "Mobile"
},
"shareholderCode": "20000000-0000-0000-0000-000000000002",
"shareholderReference": "SHREF02"
}
],
"taxId": "T123456"
},
"email": "[email protected]",
"merchantCategoryCode": "9876",
"metadata": {
"MetaDataKey2": "MetaDataValue2",
"MetaDataKey1": "MetaDataValue1"
},
"payoutMethods": [
{
"merchantAccount": "MA00001",
"payoutMethodCode": "PITC000001",
"payoutMethodType": "CardToken",
"recurringDetailReference": "RDR000001",
"shopperReference": "SR000001"
}
],
"phoneNumber": {
"phoneCountryCode": "NL",
"phoneNumber": "858888138",
"phoneType": "Landline"
},
"webAddress": "https:\/\/adyen.com"
},
"accountHolderStatus": {
"status": "Active",
"statusReason": "Test Reason",
"processingState": {
"disabled": false,
"processedFrom": {
"currency": "EUR",
"value": 10
},
"processedTo": {
"currency": "EUR",
"value": 100
},
"tierNumber": 2
},
"payoutState": {
"allowPayout": true,
"payoutLimit": {
"currency": "EUR",
"value": 100
},
"disabled": false,
"tierNumber": 2
}
},
"description": "Test reference - Test description",
"legalEntity": "Business",
"primaryCurrency": "EUR",
"verification": {
"accountHolder": {
"checks": [
{
"type": "COMPANY_VERIFICATION",
"status": "PENDING"
}
]
},
"shareholders": [
{
"checks": [
{
"type": "IDENTITY_VERIFICATION",
"status": "PASSED"
},
{
"type": "PASSPORT_VERIFICATION",
"status": "AWAITING_DATA",
"requiredFields": [
"field name: document, shareholder: 10000000-0000-0000-0000-000000000001, field: AccountHolderDetails.BusinessDetails.Shareholders.Document.document"
]
}
],
"shareholderCode": "10000000-0000-0000-0000-000000000001"
},
{
"checks": [
{
"type": "IDENTITY_VERIFICATION",
"status": "FAILED",
"summary": {
"kycCheckCode": 1,
"kycCheckDescription": "Test item1: account holder address is not found"
}
}
],
"shareholderCode": "20000000-0000-0000-0000-000000000002"
}
],
"bankAccounts": [
{
"checks": [
{
"type": "BANK_ACCOUNT_VERIFICATION",
"status": "AWAITING_DATA",
"requiredFields": [
"field name: bankBicSwift, field: AccountHolderDetails.BankAccountDetails.bankBicSwift",
"field name: bankName, field: AccountHolderDetails.BankAccountDetails.bankName"
]
}
],
"bankAccountUUID": "10000000-0000-0000-0000-000000000001"
},
{
"checks": [
{
"type": "BANK_ACCOUNT_VERIFICATION",
"status": "FAILED",
"summary": {
"kycCheckCode": 1,
"kycCheckDescription": "Test item1: account address is not found"
}
}
],
"bankAccountUUID": "20000000-0000-0000-0000-000000000002"
}
],
"cards": [
{
"checks": [
{
"type": "CARD_VERIFICATION",
"status": "AWAITING_DATA",
"summary": {
"kycCheckCode": 1,
"kycCheckDescription": "Test item1: account address is not found"
},
"requiredFields": [
"field name: cardToken, field: AccountHolderDetails.CardTokens.cardToken"
]
}
],
"payoutMethodCode": "20000000-0000-0000-0000-000000000001"
}
]
}
}
}
Note
If this already exists in the library, feel free to point me in the right direction. Thanks in advance for all your help!
Describe the bug
The version says 2.0.0 instead of 2.1.0
https://github.com/Adyen/adyen-go-api-library/blob/v2.1.0/src/common/configuration.go#L64
I would like to use the Go-libarary with Cloud-Terminals from Adyen
The Readme in the develop branch says:
The Library supports all APIs under the following services:
[...]
Cloud-based Terminal API: Our point-of-sale integration.
But I cannot find anything regarding cloud-terminals in the code, beside a configuration for the TerminalApiCloudEndpoint
Is there any plans for supporting Cloud-Terminals in the near future ?
Describe the bug
Attempting this flow: https://docs.adyen.com/online-payments/3d-secure/other-3ds-flows/authentication-only#authorise-the-payment-with-adyen
You cannot send false
for ThreeDSAuthenticationOnly:
False is omitted and downstream default behaviour must be the opposite (true
).
It works as expected if I remove omitempty
.
To Reproduce
Steps to reproduce the behavior:
Try a submit a request with false - the value is not included.
Expected behavior
N/A
Screenshots
N/A
Desktop (please complete the following information):
N/A
Smartphone (please complete the following information):
N/A
Additional context
Describe the bug
API -> /listRecurringDetails
Execution ---->>>
res, httpRes, err := client.Recurring.ListRecurringDetails(&recurring.RecurringDetailsRequest{
MerchantAccount: MerchantAccount,
Recurring: &recurring.RecurringType{
Contract: "RECURRING",
},
ShopperReference: "ref",
})
res.Details value is null
The reason is that the parts of the res.body and RecurringDetailsResult models do not match.
res.body --->>>
"details": [
{
"RecurringDetail": { -->> this part..
"additionalData": {
"cardBin": "411111"
},
...
Please modify..
Thanks
Describe the bug
client.Checkout.Payments(req)
returns a nil
interface (PaymentResponseActionOneOfInterface
) for actions when it api returns something. Either PaymentResponseActionOneOfInterface
does not correctly get attached or I'm doing it wrong.
When is try to serialize the res.Action
, it's always null. Debugging it also returns a nil interface.
(*checkout.PaymentResponseActionOneOf)(0xc0004a2530)({
PaymentResponseActionOneOfInterface: (interface {}) <nil>
})
The API does return something like this for the request:
{
"resultCode": "Pending",
"action": {
"paymentData": "Ab0...",
"paymentMethodType": "paypal",
"sdkData": {
"token": "EC-3.."
},
"type": "sdk"
},
"details": [
{
"key": "token",
"type": "text"
}
],
"outputDetails": {
"token": "EC-3.."
},
"paymentData": "Ab0...",
}
To Reproduce
t.Run("Create a valid paypal Request", func(t *testing.T) {
req := &checkout.PaymentRequest{
Reference: "123456781235",
Amount: checkout.Amount{
Value: 1250,
Currency: "EUR",
},
CountryCode: "NL",
MerchantAccount: MerchantAccount,
Channel: "Web",
ReturnUrl: "http://localhost:3000/redirect",
PaymentMethod: map[string]interface{}{
"subtype": "sdk",
"type": "paypal",
},
}
require.Nil(t, req.ApplicationInfo)
res, httpRes, err := client.Checkout.Payments(req)
require.Nil(t, err)
require.NotNil(t, httpRes)
assert.Equal(t, 200, httpRes.StatusCode)
require.NotNil(t, res)
// @todo: validate real paypal response
require.NotNil(t, res.Action.PaymentResponseActionOneOfInterface)
require.NotNil(t, res.PaymentData)
// check if req has ApplicationInfo added to it
require.NotNil(t, req.ApplicationInfo)
require.NotNil(t, req.ApplicationInfo.AdyenLibrary)
require.Equal(t, common.LibName, req.ApplicationInfo.AdyenLibrary.Name)
require.Equal(t, common.LibVersion, req.ApplicationInfo.AdyenLibrary.Version)
})
Expected behavior
Give me back the actions from the api so I can handle it in the frontend
Is your feature request related to a problem? Please describe.
Checkout API v68 added the /sessions endpoint needed for the new v5.0.0 Drop In to simplify the payment request flow.
Describe the solution you'd like
sessions endpoint should be supported by this go-api-library
Describe alternatives you've considered
For now we use the pre v5.0.0 payment request flow
I see that you have merged the hmacvalidator code - do you have a timeline for the next release so I can use it in my source code?
NewAPIClient
methodsIs your feature request related to a problem? Please describe.
Can we use the open API generator to also generate strongly typed types for the Platform notifications?
https://docs.adyen.com/api-explorer/#/NotificationService/v5/overview
I think the Content field will initially be pretty cumbersome so I'm not sure if the generator you used would be good for this.
Describe the solution you'd like
Use the open-api generator to generate types for platform notifications
Describe alternatives you've considered
I initially was going to submit a PR using the existing notifications.NotificationRequestItemData but I noticed there were actually a few discrepancies
Additionally, we can just build those models on our side for decoding but would be great to consolidate in library. I'm also happy to help build this!
Additional context
N/A
Is your feature request related to a problem? Please describe.
I saw that there are some Dispute APIs available.
Describe the solution you'd like
Is it possible to support them through the library?
Describe alternatives you've considered
I can write my own HTTP calls but would be nice to just use this library with strongly typed responses for the different models
Additional context
Add any other context or screenshots about the feature request here.
Some payment methods (like Paypal) return this field, but it is not part of the CheckoutPaymentsAction.
see https://docs.adyen.com/payment-methods/paypal/web-component#-payments-response
First of all we are using Adyen Go API Library in our project. We have a function that returns this request model as stated below:
https://github.com/Adyen/adyen-go-api-library/blob/develop/src/checkout/model_payment_request.go
We want to make storing payment methods optional. When we try to pass false value into this struct it omits by default that's why it always saves the card.
The problem is the definition of StorePaymentMethod in PaymentRequest struct, line 113.
StorePaymentMethod bool json:"storePaymentMethod,omitempty"
For example, we are trying to return a PaymentRequest struct as we shared in attached image 1. When we send a request to this endpoint with these parameters it saves the card anyways.
Our solution is changing the definition of StorePaymentMethod in PaymentRequest struct as we state below:
StorePaymentMethod *bool json:"storePaymentMethod,omitempty"
Using pointer in struct fields provides us sending false value in StorePaymentMethod as PaymentRequest and we will use it as we shared in attached image 2.
If Adyen developers can update this repository as we requested, our problem will be resolved.
Hi @KadoBOT @rikterbeek here is the current progress and tasks to do
Describe the bug
The SetIdempotencyKey function on APIClient sets a header that is shared between all goroutines that might share the Adyen client. In a scenario where for example a http Handler will do an Adyen call, this can potentially distort what IdempotencyKey is being used between multiple goroutines.
To Reproduce
https://gist.github.com/aleksen/1ee7edf57a940be8fc1c0c361d3c7126
This code will first output some requests that have either missing or wrong idempotency-key, and then crash with "concurrent map writes", stemming from /src/common/configuration.go:104 where the DefaultHeader is being set.
This gist has been tested with commit 255a560.
Expected behavior
Expected behaviour is that the correct idempotency key is sent with the correct request. Perhaps the SetIdempotencyKey function on the client is not the best approach.
@KadoBOT if we support any other mode of auth, please add it here
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.