getlago / lago-go-client Goto Github PK
View Code? Open in Web Editor NEWLago Go Client
License: MIT License
Lago Go Client
License: MIT License
The API spec calls for a ChargeModel of "volumme" however the ChargeModel type does not have a valid "Volume" type.
Although "volume" is a valid ChargeModel value (as the type is a string) it would be nice it was referenced by an enum value.
Code Link:
Lines 9 to 16 in 20f7c31
Describe the bug
The Create Customer function is constantly failing with 422
error code
I have also noticed that it doesn't seem to be executing the same sql as when the equivalent curl
command is used to create a customer.
Also not that if fails regardless of whether setting sync
or sync_with_provider
to true
.
To Reproduce
example go code
(you will note that the go code shown at https://docs.getlago.com/api-reference/customers/create does not work because the Metadata
value is incorrectly formatted, and also the VatRate
field is missing a comma at the end of the line)
lagoClient := lago.New().
SetBaseURL("http://my.lago.local:3000").
SetApiKey("xxxxx-xxxx-xxxxx-xxxx-xxxxxxxx")
var theCustomerMetadataArray = []lago.CustomerMetadataInput{lago.CustomerMetadataInput{ Key: "coolkey", Value: "coolvalue", DisplayInInvoice: true,},}
customerInput := &lago.CustomerInput{
ExternalID: "7ce34fa7-c6ef-48ca-968c-a367bcdc4477",
Name: "otra cool customer",
Email: "[email protected]",
AddressLine1: "Address Line 1",
AddressLine2: "Address Line 2",
City: "Paris",
Country: "France",
Currency: "EUR",
State: "Paris",
Zipcode: "75001",
LegalName: "Get dis",
LegalNumber: "654321",
TaxIdentificationNumber: "EU987654321",
Phone: "+330100000000",
Timezone: "Europe/Paris",
URL: "https://getlago.com",
Metadata: theCustomerMetadataArray,
BillingConfiguration: lago.CustomerBillingConfigurationInput{
InvoiceGracePeriod: 3,
PaymentProvider: lago.PaymentProviderStripe,
Sync: true,
SyncWithProvider: true,
DocumentLocale: "en",
},
}
var theError *lago.Error
theContext := context.Background()
customer, theError := lagoClient.Customer().Create(theContext, customerInput)
produces example sql log (notice that no stripe customer creation task/job is first created as seen in the subsequent curl example)
INFO -- : [3bd84174-4a93-4230-b684-0d3b5ee104de] {"method":"POST","path":"/api/v1/customers","format":"json","controller":"Api::V1::CustomersController","action":"create","status":422,"duration":752.39,"view":2.06,"db":268.5,"ddsource":"ruby","params":{"customer":{"external_id":"7ce34fa7-c6ef-48ca-968c-a367bcdc4477","name":"otra cool customer","email":"[email protected]","address_line1":"Address Line 1","address_line2":"Address Line 2","city":"Paris","zipcode":"75001","state":"Paris","country":"France","legal_name":"Get dis","legal_number":"654321","tax_identification_number":"EU987654321","phone":"+330100000000","url":"https://getlago.com","currency":"EUR","timezone":"Europe/Paris","metadata":[{"key":"coolkey","value":"coolvalue","display_in_invoice":true}],"billing_configuration":{"invoice_grace_period":3,"payment_provider":"stripe","document_locale":"en"}}},"sql_queries":"'Organization Load (3.1) SELECT \"organizations\".* FROM \"organizations\" WHERE \"organizations\".\"api_key\" = $1 LIMIT $2\nMembership Load (4.74) SELECT \"memberships\".* FROM \"memberships\" WHERE \"memberships\".\"organization_id\" = $1 ORDER BY \"memberships\".\"created_at\" ASC LIMIT $2\nCustomer Load (6.95) SELECT \"customers\".* FROM \"customers\" WHERE \"customers\".\"deleted_at\" IS NULL AND \"customers\".\"organization_id\" = $1 AND \"customers\".\"external_id\" = $2 LIMIT $3\nTRANSACTION (0.84) BEGIN\nCustomer Exists? (2.25) SELECT 1 AS one FROM \"customers\" WHERE \"customers\".\"external_id\" = $1 AND \"customers\".\"organization_id\" = $2 AND \"customers\".\"deleted_at\" IS NULL LIMIT $3\nTRANSACTION (1.28) COMMIT'","sql_queries_count":6}
example curl
command
curl --location --request POST "$LAGO_URL/api/v1/customers" \
--header "Authorization: Bearer $API_KEY" \
--header 'Content-Type: application/json' \
--data-raw '{ "customer": { "external_id": "7eb02857-a71e-4ea2-bcf9-57d3a41bc6ba", "address_line1": "5230 Penfield Ave", "address_line2": "", "city": "Woodland Hills", "country": "US", "currency": "USD", "email": "[email protected]",
"legal_name": "Coleman-Blair",
"legal_number": "49-008-2965",
"tax_identification_number": "EU123456789",
"logo_url": "http://hooli.com/logo.png",
"name": "Gavin Belson",
"phone": "1-171-883-3711 x245",
"state": "CA",
"timezone": "Europe/Paris",
"url": "http://hooli.com",
"zipcode": "91364",
"billing_configuration": {
"invoice_grace_period": 3,
"payment_provider": "stripe",
"sync": true,
"sync_with_provider": true,
"document_locale": "en",
"vat_rate": 12.5
},
"metadata": [
{
"key": "Purchase Order",
"value": "123456789",
"display_in_invoice": true
}
produces the following sql in the logs (notice the stripe customer creation job is also created first as well as the difference in sql)
I, [2023-07-11T00:05:39.220454 #11] INFO -- : [67ae8abf-d8b3-4247-8acc-dee92ef1650c] [ActiveJob] [PaymentProviderCustomers::StripeCrea
teJob] [009a9b28-77b7-4eb1-935d-3e258f63e0cc] [membership/d5a1e22a-e234-4b8b-a95b-3a2cb66001d4] Performing PaymentProviderCustomers::St
ripeCreateJob (Job ID: 009a9b28-77b7-4eb1-935d-3e258f63e0cc) from Sidekiq(providers) enqueued at with arguments: #<GlobalID:0x00007fb2
e5960d80 @uri=#<URI::GID gid://lago-api/PaymentProviderCustomers::StripeCustomer/68ef831e-1f1f-4935-a2fe-da6961cba3fe>>
I, [2023-07-11T00:05:39.979603 #11] INFO -- : [67ae8abf-d8b3-4247-8acc-dee92ef1650c] [ActiveJob] [PaymentProviderCustomers::StripeCrea
teJob] [009a9b28-77b7-4eb1-935d-3e258f63e0cc] [membership/d5a1e22a-e234-4b8b-a95b-3a2cb66001d4] [membership/d5a1e22a-e234-4b8b-a95b-3a2
cb66001d4] Sidekiq 7.0.8 connecting to Redis with options {:size=>5, :pool_name=>"internal", :url=>"redis://redis:6379", :pool_timeout=
>5}
I, [2023-07-11T00:05:39.998027 #11] INFO -- : [67ae8abf-d8b3-4247-8acc-dee92ef1650c] [ActiveJob] [PaymentProviderCustomers::StripeCrea
teJob] [009a9b28-77b7-4eb1-935d-3e258f63e0cc] [membership/d5a1e22a-e234-4b8b-a95b-3a2cb66001d4] [membership/d5a1e22a-e234-4b8b-a95b-3a2
cb66001d4] Enqueued PaymentProviderCustomers::StripeCheckoutUrlJob (Job ID: ffea9083-5913-41bb-b27e-b1c84b08f52c) to Sidekiq(providers)
with arguments: #<GlobalID:0x00007fb2e580ae68 @uri=#<URI::GID gid://lago-api/PaymentProviderCustomers::StripeCustomer/68ef831e-1f1f-49
35-a2fe-da6961cba3fe>>
I, [2023-07-11T00:05:39.998613 #11] INFO -- : [67ae8abf-d8b3-4247-8acc-dee92ef1650c] [ActiveJob] [PaymentProviderCustomers::StripeCrea
teJob] [009a9b28-77b7-4eb1-935d-3e258f63e0cc] [membership/d5a1e22a-e234-4b8b-a95b-3a2cb66001d4] Performed PaymentProviderCustomers::Str
ipeCreateJob (Job ID: 009a9b28-77b7-4eb1-935d-3e258f63e0cc) from Sidekiq(providers) in 778.82ms
I, [2023-07-11T00:05:40.009565 #11] INFO -- : [67ae8abf-d8b3-4247-8acc-dee92ef1650c] [ActiveJob] [membership/d5a1e22a-e234-4b8b-a95b-3
a2cb66001d4] Enqueued SegmentTrackJob (Job ID: 660dea74-7afd-43e0-8a22-f1b3907f86e3) to Sidekiq(default) with arguments: {:membership_i
d=>"membership/d5a1e22a-e234-4b8b-a95b-3a2cb66001d4", :event=>"customer_created", :properties=>{:customer_id=>"5734238d-c086-4678-aaca-
c92f71d58636", :created_at=>Tue, 11 Jul 2023 00:05:38.551691000 UTC +00:00, :payment_provider=>"stripe", :organization_id=>"91886c78-fe
0b-4961-84a3-08a784e0ba94"}}
I, [2023-07-11T00:05:40.018760 #11] INFO -- : [67ae8abf-d8b3-4247-8acc-dee92ef1650c] {"method":"POST","path":"/api/v1/customers","form
at":"*/*","controller":"Api::V1::CustomersController","action":"create","status":200,"duration":1679.74,"view":6.92,"db":511.35,"ddsour
ce":"ruby","params":{"customer":{"external_id":"7eb02857-a71e-4ea2-bcf9-57d3a41bc6ba","address_line1":"5230 Penfield Ave","address_line
2":"","city":"Woodland Hills","country":"US","currency":"USD","email":"[email protected]","legal_name":"Coleman-Blair","legal_numbe
r":"49-008-2965","tax_identification_number":"EU123456789","logo_url":"http://hooli.com/logo.png","name":"Gavin Belson","phone":"1-171-
883-3711 x245","state":"CA","timezone":"Europe/Paris","url":"http://hooli.com","zipcode":"91364","billing_configuration":{"invoice_grac
e_period":3,"payment_provider":"stripe","sync":true,"sync_with_provider":true,"document_locale":"en","vat_rate":12.5},"metadata":[{"key
":"Purchase Order","value":"123456789","display_in_invoice":true}]}},"sql_queries":"'Organization Load (2.03) SELECT \"organizations\".
* FROM \"organizations\" WHERE \"organizations\".\"api_key\" = $1 LIMIT $2\nMembership Load (8.93) SELECT \"memberships\".* FROM \"memb
erships\" WHERE \"memberships\".\"organization_id\" = $1 ORDER BY \"memberships\".\"created_at\" ASC LIMIT $2\nCustomer Load (1.39) SEL
ECT \"customers\".* FROM \"customers\" WHERE \"customers\".\"deleted_at\" IS NULL AND \"customers\".\"organization_id\" = $1 AND \"cust
omers\".\"external_id\" = $2 LIMIT $3\nTRANSACTION (0.48) BEGIN\nCustomer Exists? (1.44) SELECT 1 AS one FROM \"customers\" WHERE \"cus
tomers\".\"external_id\" = $1 AND \"customers\".\"organization_id\" = $2 AND \"customers\".\"deleted_at\" IS NULL LIMIT $3\n (1.13) SEL
ECT pg_try_advisory_xact_lock(1394491257,0) AS t54a442a1d8bb8a76ce2788d06b48ee5b /* customer_lock */\nCustomer Pluck (1.25) SELECT \"cu
stomers\".\"sequential_id\" FROM \"customers\" WHERE \"customers\".\"organization_id\" = $1 AND \"customers\".\"sequential_id\" IS NOT
NULL ORDER BY \"customers\".\"sequential_id\" DESC LIMIT $2\nCustomer Exists? (1.33) SELECT 1 AS one FROM \"customers\" WHERE \"custome
rs\".\"organization_id\" = $1 AND \"customers\".\"sequential_id\" = $2 LIMIT $3\nCustomer Create (43.2) INSERT INTO \"customers\" (\"ex
ternal_id\", \"name\", \"organization_id\", \"created_at\", \"updated_at\", \"country\", \"address_line1\", \"address_line2\", \"state\
", \"zipcode\", \"email\", \"city\", \"url\", \"phone\", \"logo_url\", \"legal_name\", \"legal_number\", \"vat_rate\", \"payment_provid
er\", \"slug\", \"sequential_id\", \"currency\", \"invoice_grace_period\", \"timezone\", \"deleted_at\", \"document_locale\", \"tax_ide
ntification_number\") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23,
$24, $25, $26, $27) RETURNING \"id\"\nPaperTrail::Version Create (48.44) INSERT INTO \"versions\" (\"item_type\", \"item_id\", \"event
\", \"whodunnit\", \"object\", \"object_changes\", \"created_at\") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING \"id\"\nPaperTrail::Ve
rsion Count (2.44) SELECT COUNT(*) FROM \"versions\" WHERE \"versions\".\"item_type\" = $1 AND \"versions\".\"item_id\" = $2 AND \"vers
ions\".\"event\" != $3\nCustomer Exists? (1.6) SELECT 1 AS one FROM \"customers\" WHERE \"customers\".\"external_id\" = $1 AND \"custom
ers\".\"id\" != $2 AND \"customers\".\"organization_id\" = $3 AND \"customers\".\"deleted_at\" IS NULL LIMIT $4\nMetadata::CustomerMeta
data Exists? (3.0) SELECT 1 AS one FROM \"customer_metadata\" WHERE \"customer_metadata\".\"key\" = $1 AND \"customer_metadata\".\"cust
omer_id\" = $2 LIMIT $3\nMetadata::CustomerMetadata Create (2.06) INSERT INTO \"customer_metadata\" (\"customer_id\", \"key\", \"value\
", \"display_in_invoice\", \"created_at\", \"updated_at\") VALUES ($1, $2, $3, $4, $5, $6) RETURNING \"id\"\nTRANSACTION (46.97) COMMIT
\nTRANSACTION (0.71) BEGIN\nCustomer Exists? (1.48) SELECT 1 AS one FROM \"customers\" WHERE \"customers\".\"external_id\" = $1 AND \"c
ustomers\".\"id\" != $2 AND \"customers\".\"organization_id\" = $3 AND \"customers\".\"deleted_at\" IS NULL LIMIT $4\nCustomer Update (
2.11) UPDATE \"customers\" SET \"updated_at\" = $1, \"vat_rate\" = $2, \"payment_provider\" = $3, \"document_locale\" = $4 WHERE \"cust
omers\".\"id\" = $5\nPaperTrail::Version Create (93.1) INSERT INTO \"versions\" (\"item_type\", \"item_id\", \"event\", \"whodunnit\",
\"object\", \"object_changes\", \"created_at\") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING \"id\"\nPaperTrail::Version Count (2.09)
SELECT COUNT(*) FROM \"versions\" WHERE \"versions\".\"item_type\" = $1 AND \"versions\".\"item_id\" = $2 AND \"versions\".\"event\" !=
$3\nTRANSACTION (23.92) COMMIT\nPaymentProviders::StripeProvider Load (1.83) SELECT \"payment_providers\".* FROM \"payment_providers\"
WHERE \"payment_providers\".\"type\" = $1 AND \"payment_providers\".\"organization_id\" = $2 LIMIT $3\nPaymentProviderCustomers::Strip
eCustomer Load (2.56) SELECT \"payment_provider_customers\".* FROM \"payment_provider_customers\" WHERE \"payment_provider_customers\".
\"type\" = $1 AND \"payment_provider_customers\".\"customer_id\" = $2 AND \"payment_provider_customers\".\"payment_provider_id\" = $3 L
IMIT $4\nTRANSACTION (9.23) BEGIN\nCustomer Load (1.09) SELECT \"customers\".* FROM \"customers\" WHERE \"customers\".\"deleted_at\" IS
NULL AND \"customers\".\"id\" = $1 LIMIT $2\nPaymentProviderCustomers::BaseCustomer Exists? (6.23) SELECT 1 AS one FROM \"payment_prov
ider_customers\" WHERE \"payment_provider_customers\".\"customer_id\" = $1 AND \"payment_provider_customers\".\"type\" = $2 LIMIT $3\nP
aymentProviderCustomers::StripeCustomer Create (2.23) INSERT INTO \"payment_provider_customers\" (\"customer_id\", \"payment_provider_i
d\", \"type\", \"provider_customer_id\", \"settings\", \"created_at\", \"updated_at\") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING \"
id\"\nTRANSACTION (60.5) COMMIT\nOrganization Load (1.31) SELECT \"organizations\".* FROM \"organizations\" WHERE \"organizations\".\"i
d\" = $1 LIMIT $2\nPaymentProviders::StripeProvider Load (1.33) SELECT \"payment_providers\".* FROM \"payment_providers\" WHERE \"payme
nt_providers\".\"type\" = $1 AND \"payment_providers\".\"organization_id\" = $2 LIMIT $3\nTRANSACTION (0.95) BEGIN\nPaymentProviderCust
omers::BaseCustomer Exists? (3.53) SELECT 1 AS one FROM \"payment_provider_customers\" WHERE \"payment_provider_customers\".\"customer_
id\" = $1 AND \"payment_provider_customers\".\"id\" != $2 AND \"payment_provider_customers\".\"type\" = $3 LIMIT $4\nPaymentProviderCus
tomers::StripeCustomer Update (1.69) UPDATE \"payment_provider_customers\" SET \"provider_customer_id\" = $1, \"updated_at\" = $2 WHERE
\"payment_provider_customers\".\"id\" = $3\nTRANSACTION (41.21) COMMIT\nTRANSACTION (0.55) BEGIN\nCustomer Exists? (1.08) SELECT 1 AS
one FROM \"customers\" WHERE \"customers\".\"external_id\" = $1 AND \"customers\".\"id\" != $2 AND \"customers\".\"organization_id\" =
$3 AND \"customers\".\"deleted_at\" IS NULL LIMIT $4\nTRANSACTION (0.72) COMMIT\nPaymentProviderCustomers::StripeCustomer Load (0.77) S
ELECT \"payment_provider_customers\".* FROM \"payment_provider_customers\" WHERE \"payment_provider_customers\".\"type\" = $1 AND \"pay
ment_provider_customers\".\"customer_id\" = $2 LIMIT $3\nMetadata::CustomerMetadata Load (0.81) SELECT \"customer_metadata\".* FROM \"c
ustomer_metadata\" WHERE \"customer_metadata\".\"customer_id\" = $1'","sql_queries_count":39}
Expected behavior
The customer should be created in both lago and stripe as is the case when using a curl
request
Support
Additional context
Not sure if it makes a difference but when checking the differences in the http requests between the go client and curl.
the go client has headers Accept: application/json, Accept-Encoding: gzip
whereas
curl just uses Accept: */*
with no specified Encoding preference either
Describe the bug
Go client returns rate:[value_is_mandatory]
while trying to create a tax code with 0% tax rate - but the API works via postman.
Expected behavior
It should be possible to set 0% as tax rate.
Describe the bug
resp.Error()
here is not returning validation errors
To Reproduce
try to create a plan with a validation error, an empty error is returned.
Expected behavior
An error with validation errors is returned.
The library is missing the method to retrieve the public key for webhook signature
We should add the method to make it easier for people using the lib to retrieve key and validate the signature
Describe the bug
Cannot create new Subscription because of the invalid date of subscription_at
subscription_at
is type of time.Time when convert to JSON it like this "2023-06-27T10:04:26.7529083+00:00"
To Reproduce
ctx := context.TODO()
now := time.Now()
result, err := client.Subscription().Create(ctx, &lago.SubscriptionInput{
ExternalCustomerID: "cus-001",
PlanCode: "plan-001",
SubscriptionAt: &now,
BillingTime: lago.Anniversary,
ExternalID: "sub-001",
Name: "Sub-001",
})
Expected behavior
Need to convert the time.Time
data to correct format or should use string
data type for subscription_at
so developer can format the time
Screenshots
NA
Support
Additional context
NA
Describe the bug
Customer input address lines json tags are not the same the same as the API expects.
The fields are currently:
AddressLine1 string `json:"address_line_1,omitempty"`
AddressLine2 string `json:"address_line_2,omitempty"`
while the API expects:
AddressLine1 string `json:"address_line1,omitempty"`
AddressLine2 string `json:"address_line2,omitempty"`
To Reproduce
Expected behavior
Go client should have the correct tags so the api can process them.
Support
Additional context
see:
https://pkg.go.dev/github.com/getlago/[email protected]#CustomerInput
and the curl example here:
https://doc.getlago.com/docs/api/customers/create-customer
Requesting filters support.
First of all: Thanks for your great application. I am quite happy I found it!
Describe the bug
Listing the wallet(s) of a user
lago.Wallet().GetList()
GET /api/v1/wallets
fails. Not only ExternalCustomerID
should be a string (but an integer is demanded). The call is not working even if the type is changed to string manually. Looks to me as if this required (!) parameter is not properly forwarded to the api.
To Reproduce
lago.Wallet().GetList()
(will already complain that ExternalCustomerID should be an integer)Expected behavior
Given ExternalCustomerID was provided. JSON formatted as lagoClient.WalletResult{}
Support
Hi Team, hopefully this is right place to ask, if not, I'd appreciate if you can direct me.
I'm the founder of cloudquery.io, a high performance open source ELT framework.
Our users are interested in a Lago plugin, but as we cannot maintain all the plugins ourselves, I was curious if this would be an interesting collaboration, where we would help implement an initial source plugin, and you will help maintain it.
This will give your users the ability to sync Lago data to any of their datalakes/data-warehouses/databases easily using any of the growing list of CQ destination plugins.
Best,
Yevgeny
Describe the bug
When calling an endpoint that can return multiple errors (for example the event batch endpoint), RESTY can't parse the error into the error struct.
The error is:
WARN RESTY Cannot unmarshal response body: json: cannot unmarshal object into Go struct field Error.error_details of type []string
The JSON response of the error:
{
"status": 422,
"error": "Unprocessable Entity",
"code": "validation_errors",
"error_details": {
"0": {
"transaction_id": [
"value_already_exist"
]
},
"1": {
"transaction_id": [
"value_already_exist"
]
},
"2": {
"transaction_id": [
"value_already_exist"
]
}
}
}
To Reproduce
Call the event batch endpoint with multiple events that already exist.
Expected behavior
Receiving an error struct that contains all the errors in the response.
Describe the bug
When creating a new customer by default "card" and "sepa" are added as payment methods for stripe payment provider. Which causes an issue for people outside europe.
To Reproduce
Expected behavior
Successful creation of invoice.
Screenshots
{ "webhook_type": "customer.payment_provider_error", "object_type": "payment_provider_customer_error", "payment_provider_customer_error": { "lago_customer_id": "xyz", "external_customer_id": "xyz", "payment_provider": "stripe", "provider_error": { "message": "The payment method type provided: sepa_debit is invalid. Please ensure the provided type is activated in your dashboard (https://dashboard.stripe.com/account/payments/settings) and your account is enabled for any preview features that you are trying to use. See https://stripe.com/docs/payments/payment-methods/integration-options for supported payment method, currency, and country combinations.", "error_code": null } } }
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.