-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcurrencycloud.go
More file actions
337 lines (264 loc) · 13.6 KB
/
Copy pathcurrencycloud.go
File metadata and controls
337 lines (264 loc) · 13.6 KB
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
// Package currencycloud provides a production-grade Go client for the
// Currencycloud v2 API (https://developer.currencycloud.com).
//
// This file is the only file in the root package. All implementation lives in
// sub-packages following DDD architecture:
//
// - domain/* — entities, value objects, repository interfaces
// - infrastructure/* — HTTP transport, auth, config, API adapters
// - internal/* — private test helpers
// - tests/* — unit and integration test suites
//
// Quick start:
//
// client, err := currencycloud.NewClient("user@example.com", "api-key",
// currencycloud.WithEnvironment(currencycloud.Production),
// )
// defer client.Logout(context.Background())
// balance, _ := client.Balances.Get(ctx, "EUR")
//
// // Sub-account scoping:
// sub := client.OnBehalfOf("contact-uuid")
// conv, _ := sub.Conversions.Create(ctx, conversion.CreateParams{...})
package currencycloud
import (
"context"
"github.com/iamkanishka/currencycloud-client-go/domain/account"
"github.com/iamkanishka/currencycloud-client-go/domain/balance"
"github.com/iamkanishka/currencycloud-client-go/domain/beneficiary"
"github.com/iamkanishka/currencycloud-client-go/domain/contact"
"github.com/iamkanishka/currencycloud-client-go/domain/conversion"
"github.com/iamkanishka/currencycloud-client-go/domain/funding"
"github.com/iamkanishka/currencycloud-client-go/domain/payment"
"github.com/iamkanishka/currencycloud-client-go/domain/rate"
"github.com/iamkanishka/currencycloud-client-go/domain/reference"
"github.com/iamkanishka/currencycloud-client-go/domain/reporting"
"github.com/iamkanishka/currencycloud-client-go/domain/shared"
"github.com/iamkanishka/currencycloud-client-go/domain/transaction"
"github.com/iamkanishka/currencycloud-client-go/domain/transfer"
"github.com/iamkanishka/currencycloud-client-go/domain/webhook"
infraapi "github.com/iamkanishka/currencycloud-client-go/infrastructure/api"
"github.com/iamkanishka/currencycloud-client-go/infrastructure/auth"
"github.com/iamkanishka/currencycloud-client-go/infrastructure/config"
httpinfra "github.com/iamkanishka/currencycloud-client-go/infrastructure/http"
)
// ─── Configuration re-exports ─────────────────────────────────────────────────
// Environment selects the Currencycloud API environment.
type Environment = config.Environment
// Available environments.
const (
// Demo is the sandbox environment (devapi.currencycloud.com).
Demo Environment = config.Demo
// Production is the live environment (api.currencycloud.com).
Production Environment = config.Production
)
// Option is a functional option accepted by NewClient.
type Option = config.Option
// WithEnvironment sets the API environment. Default: Demo.
var WithEnvironment = config.WithEnvironment
// WithTimeout sets the HTTP request timeout. Default: 30s.
var WithTimeout = config.WithTimeout
// WithConnectTimeout sets the TCP dial timeout. Default: 5s.
var WithConnectTimeout = config.WithConnectTimeout
// WithMaxRetries sets the maximum retry attempts on transient errors. Default: 5.
var WithMaxRetries = config.WithMaxRetries
// WithRetryBaseDelay sets the initial exponential backoff delay. Default: 500ms.
var WithRetryBaseDelay = config.WithRetryBaseDelay
// WithRetryMaxDelay caps the exponential backoff delay. Default: 30s.
var WithRetryMaxDelay = config.WithRetryMaxDelay
// WithTokenRefreshBuffer sets how early to refresh the auth token. Default: 2m.
var WithTokenRefreshBuffer = config.WithTokenRefreshBuffer
// WithUserAgent overrides the HTTP User-Agent header.
var WithUserAgent = config.WithUserAgent
// WithMaxIdleConns sets the HTTP connection pool size. Default: 100.
var WithMaxIdleConns = config.WithMaxIdleConns
// WithBaseURL overrides the API base URL (for local/mock server testing).
var WithBaseURL = config.WithBaseURL
// ─── Domain param type aliases ────────────────────────────────────────────────
// CreateAccountParams holds data for creating a sub-account.
type CreateAccountParams = account.CreateParams
// UpdateAccountParams holds data for updating an account.
type UpdateAccountParams = account.UpdateParams
// FindAccountsParams holds filter criteria for Accounts.Find.
type FindAccountsParams = account.FilterParams
// FindBalancesParams holds filter criteria for Balances.Find.
type FindBalancesParams = balance.FilterParams
// CreateBeneficiaryParams holds data for creating a beneficiary.
type CreateBeneficiaryParams = beneficiary.CreateParams
// FindBeneficiariesParams holds filter criteria for Beneficiaries.Find.
type FindBeneficiariesParams = beneficiary.FilterParams
// VerifyBeneficiaryParams holds data for Confirmation of Payee.
type VerifyBeneficiaryParams = beneficiary.VerifyParams
// CreateContactParams holds data for creating a contact.
type CreateContactParams = contact.CreateParams
// FindContactsParams holds filter criteria for Contacts.Find.
type FindContactsParams = contact.FilterParams
// CreateConversionParams holds data for booking a conversion.
type CreateConversionParams = conversion.CreateParams
// FindConversionsParams holds filter criteria for Conversions.Find.
type FindConversionsParams = conversion.FilterParams
// FindProfitAndLossParams holds filter criteria for Conversions.ProfitAndLoss.
type FindProfitAndLossParams = conversion.ProfitAndLossParams
// CreatePaymentParams holds data for creating a payment.
type CreatePaymentParams = payment.CreateParams
// FindPaymentsParams holds filter criteria for Payments.Find.
type FindPaymentsParams = payment.FilterParams
// GetDeliveryDateParams holds data for Payments.GetDeliveryDate.
type GetDeliveryDateParams = payment.DeliveryDateParams
// BasicRateParams holds parameters for Rates.GetBasic.
type BasicRateParams = rate.BasicParams
// DetailedRateParams holds parameters for Rates.GetDetailed.
type DetailedRateParams = rate.DetailedParams
// BeneficiaryRequiredDetailsParams holds parameters for Reference.GetBeneficiaryRequiredDetails.
type BeneficiaryRequiredDetailsParams = reference.BeneficiaryRequiredDetailsParams
// ConversionDatesParams holds parameters for Reference.GetConversionDates.
type ConversionDatesParams = reference.ConversionDatesParams
// PaymentDatesParams holds parameters for Reference.GetPaymentDates.
type PaymentDatesParams = reference.PaymentDatesParams
// PayerRequiredDetailsParams holds parameters for Reference.GetPayerRequiredDetails.
type PayerRequiredDetailsParams = reference.PayerRequiredDetailsParams
// BankDetailsParams holds parameters for Reference.GetBankDetails.
type BankDetailsParams = reference.BankDetailsParams
// CreateTransferParams holds data for creating a transfer.
type CreateTransferParams = transfer.CreateParams
// FindTransfersParams holds filter criteria for Transfers.Find.
type FindTransfersParams = transfer.FilterParams
// FindTransactionsParams holds filter criteria for Transactions.Find.
type FindTransactionsParams = transaction.FilterParams
// FindFundingAccountsParams holds filter criteria for Funding.FindFundingAccounts.
type FindFundingAccountsParams = funding.FilterParams
// ─── Error type aliases ───────────────────────────────────────────────────────
// APIError is the base error embedded in all concrete API error types.
type APIError = shared.APIError
// FieldError is a per-field validation error returned by the API.
type FieldError = shared.FieldError
// AuthenticationError is returned on HTTP 401.
type AuthenticationError = shared.AuthenticationError
// ForbiddenError is returned on HTTP 403.
type ForbiddenError = shared.ForbiddenError
// BadRequestError is returned on HTTP 400.
type BadRequestError = shared.BadRequestError
// NotFoundError is returned on HTTP 404.
type NotFoundError = shared.NotFoundError
// TooManyRequestsError is returned on HTTP 429. Check RetryAfter.
type TooManyRequestsError = shared.TooManyRequestsError
// InternalServerError is returned on HTTP 5xx.
type InternalServerError = shared.InternalServerError
// NetworkError is returned on transport failures.
type NetworkError = shared.NetworkError
// UnexpectedError wraps any HTTP status not covered by the concrete types above.
type UnexpectedError = shared.UnexpectedError
// IsRetryable reports whether err is a transient error worth retrying.
var IsRetryable = shared.IsRetryable
// ─── Webhook helpers ──────────────────────────────────────────────────────────
// ErrInvalidSignature is returned by VerifyWebhook when the HMAC does not match.
var ErrInvalidSignature = webhook.ErrInvalidSignature
// ErrTimestampTooOld is returned by VerifyWebhook when the timestamp exceeds MaxAge.
var ErrTimestampTooOld = webhook.ErrTimestampTooOld
// ErrMissingHeaders is returned by VerifyWebhook when required headers are absent.
var ErrMissingHeaders = webhook.ErrMissingHeaders
// VerifyWebhook verifies the HMAC-SHA256 signature of an incoming webhook delivery.
var VerifyWebhook = webhook.Verify
// ComputeWebhookSignature computes the expected HMAC-SHA256 signature for a payload.
var ComputeWebhookSignature = webhook.ComputeSignature
// ParseWebhookPayload decodes a raw webhook body into a Payload struct.
var ParseWebhookPayload = webhook.Parse
// ─── HTTP param helpers ───────────────────────────────────────────────────────
// Params builds url.Values from alternating key/value string pairs,
// skipping pairs where the value is empty.
var Params = httpinfra.Params
// ParamsFromMap builds url.Values from a string map, skipping empty values.
var ParamsFromMap = httpinfra.FromMap
// ─── Client ───────────────────────────────────────────────────────────────────
// Client is the main API client. It is goroutine-safe and should be shared.
// All service groups expose domain repository interfaces directly, so callers
// can substitute mock implementations in tests.
type Client struct {
// Accounts manages house and sub-accounts.
Accounts account.Repository
// Balances queries currency balances.
Balances balance.Repository
// Beneficiaries manages payment recipients.
Beneficiaries beneficiary.Repository
// Contacts manages account contacts.
Contacts contact.Repository
// Conversions manages FX trades.
Conversions conversion.Repository
// Funding provides inbound fund / SSI information.
Funding funding.Repository
// Payments manages outbound payments.
Payments payment.Repository
// Payers retrieves sender details for inbound payments.
Payers *infraapi.PayerAdapter
// Rates queries FX rates.
Rates rate.Repository
// Reference provides static lookup data.
Reference reference.Repository
// Reporting generates async conversion and payment reports.
Reporting reporting.Repository
// Transactions queries the unified ledger.
Transactions transaction.Repository
// Transfers moves funds between accounts.
Transfers transfer.Repository
// Withdrawals manages ACH pull-of-funds from linked US bank accounts.
Withdrawals *infraapi.WithdrawalAdapter
sess *auth.Session
cfg *config.Config
transport *httpinfra.Transport
}
// NewClient creates a Client from the given credentials and options.
// Authentication is lazy — the first API call triggers login.
//
// client, err := currencycloud.NewClient(
// "user@example.com", "api-key",
// currencycloud.WithEnvironment(currencycloud.Production),
// currencycloud.WithTimeout(20*time.Second),
// )
func NewClient(loginID, apiKey string, opts ...Option) (*Client, error) {
cfg, err := config.New(loginID, apiKey, opts...)
if err != nil {
return nil, err
}
t := httpinfra.New(cfg)
s := auth.New(cfg, t)
return buildClient(cfg, t, s, ""), nil
}
// MustNewClient is like NewClient but panics on invalid configuration.
func MustNewClient(loginID, apiKey string, opts ...Option) *Client {
c, err := NewClient(loginID, apiKey, opts...)
if err != nil {
panic(err)
}
return c
}
// OnBehalfOf returns a new Client scoped to the given contact UUID.
// The underlying session and transport are shared with the parent client.
func (c *Client) OnBehalfOf(contactID string) *Client {
return buildClient(c.cfg, c.transport, c.sess, contactID)
}
// Logout closes the server-side session. Call via defer after NewClient.
func (c *Client) Logout(ctx context.Context) error {
return c.sess.Logout(ctx)
}
func buildClient(cfg *config.Config, t *httpinfra.Transport, s *auth.Session, obo string) *Client {
b := infraapi.NewBase(t, s, cfg, obo)
return &Client{
Accounts: infraapi.NewAccountAdapter(b),
Balances: infraapi.NewBalanceAdapter(b),
Beneficiaries: infraapi.NewBeneficiaryAdapter(b),
Contacts: infraapi.NewContactAdapter(b),
Conversions: infraapi.NewConversionAdapter(b),
Funding: infraapi.NewFundingAdapter(b),
Payments: infraapi.NewPaymentAdapter(b),
Payers: infraapi.NewPayerAdapter(b),
Rates: infraapi.NewRateAdapter(b),
Reference: infraapi.NewReferenceAdapter(b),
Reporting: infraapi.NewReportingAdapter(b),
Transactions: infraapi.NewTransactionAdapter(b),
Transfers: infraapi.NewTransferAdapter(b),
Withdrawals: infraapi.NewWithdrawalAdapter(b),
sess: s,
cfg: cfg,
transport: t,
}
}