Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,9 @@ jobs:
- name: Check if credentials are available
id: check-creds
run: |
if [ -z "${{ secrets.RAIACCEPT_TEST_USERNAME }}" ] || [ -z "${{ secrets.RAIACCEPT_TEST_PASSWORD }}" ] || [ -z "${{ secrets.RAIACCEPT_TEST_CERT_BASE64 }}" ] || [ -z "${{ secrets.RAIACCEPT_TEST_KEY_BASE64 }}" ]; then
if [ -z "${{ secrets.RAIACCEPT_TEST_USERNAME }}" ] || [ -z "${{ secrets.RAIACCEPT_TEST_PASSWORD }}" ]; then
echo "skip=true" >> $GITHUB_OUTPUT
echo "⚠️ Integration tests skipped: GitHub Secrets not configured"
echo "See .github/SETUP_CI.md for setup instructions"
echo "Integration tests skipped: RAIACCEPT_TEST_USERNAME/RAIACCEPT_TEST_PASSWORD not configured"
else
echo "skip=false" >> $GITHUB_OUTPUT
fi
Expand Down
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Changelog

## 0.10.0

### Added

- **Merchant integration mode** (default): auth on `https://auth.raiaccept.com`, API on `https://trapi.raiaccept.com`, no mTLS.
- **Partner integration mode**: mTLS cert/key; auth and API on `https://api.raiaccept.com`. Auto-detected when both cert and key are provided; override with `{ authMode: 'partner' }` or `{ authMode: 'merchant' }`.
- Exported `AuthMode`, `RaiAcceptClientConfig`, `DEFAULT_AUTH_MODE`, `RAIACCEPT_URLS`, `resolveAuthMode`, `assertTlsCredentialsPair`, `assertPartnerTlsRequired`, and `validateAuthModeConfiguration`.
- Unit tests for mode-aware URL routing and mTLS behavior.
- Separate merchant and partner integration test suites (shared username/password credentials).

### Changed

- **Breaking:** Default auth mode is now `merchant`. Partner mode applies when both cert and key are provided (same as 0.9.x), or via `{ authMode: 'partner' }`.
- Partial TLS config (only cert or only key) throws `InvalidArgumentException` at construction time.
- Explicit partner mode without both cert and key throws `InvalidArgumentException` at construction time.
- Removed deprecated `RaiAcceptAPIApi.AUTH_URL` and `RaiAcceptAPIApi.API_URL`; use exported `RAIACCEPT_URLS` instead.
- `RaiAcceptService` and `RaiAcceptAPIApi` constructors accept an optional fourth argument `config?: RaiAcceptClientConfig`.
- `ErrorResponse` model accepts both partner (`message`, `code`, `details`) and trapi (`traceId`, `timestamp`, `status`, `errors`) error shapes.
- API error parsing now includes HTTP 401 and 403 in addition to 400.

### Migration from 0.9.x (partner integrations)

```typescript
// 0.9.x — implicit partner via cert + key
const service = new RaiAcceptService(httpClient, cert, key);

// 0.10.x — same call auto-detects partner; explicit flag optional
const service = new RaiAcceptService(httpClient, cert, key);
// or: new RaiAcceptService(httpClient, cert, key, { authMode: 'partner' });
```

## 0.9.5

- Partner-only SDK using `api.raiaccept.com` for auth and API with mTLS.
182 changes: 102 additions & 80 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,161 +13,183 @@ TypeScript/JavaScript SDK for RaiAccept payment gateway API.
npm install @smartbase-js/raiaccept-api-client
```

## Usage
## Integration modes

| | Merchant (default) | Partner |
|--|-------------------|---------|
| Auth | `https://auth.raiaccept.com/auth/api/*` | `https://api.raiaccept.com/auth/api/*` |
| API | `https://trapi.raiaccept.com` | `https://api.raiaccept.com` |
| mTLS | Not used | Required (cert + key) |

When both `cert` and `key` are passed to the constructor, partner mode is selected automatically. Use `{ authMode: 'merchant' }` to force merchant mode despite cert/key (e.g. testing), or `{ authMode: 'partner' }` for explicit opt-in. Providing only cert or only key, or partner mode without both cert and key, throws `InvalidArgumentException` at construction time.

## Merchant integration (default)

For direct merchant integrations — no mTLS required.

```typescript
import { RaiAcceptService } from '@smartbase-js/raiaccept-api-client';
import { RaiAcceptService, HttpClient } from '@smartbase-js/raiaccept-api-client';

// Create service instance
const service = new RaiAcceptService();
const httpClient = new HttpClient({ logger: console });
const service = new RaiAcceptService(httpClient);

const integrationContext = {
type: 'CODE',
data: {
name: 'YourShop',
version: '1.0',
vendor: 'YourVendor',
},
};

// Authenticate with your credentials
const authResult = await service.retrieveAccessTokenWithCredentials(
'your-username', // Replace with your actual username
'your-password', // Replace with your actual password
cert, // Client certificate for mTLS
key // Client private key for mTLS
'your-username',
'your-password',
integrationContext
);
const accessToken = authResult?.accessToken;

const response = await service.createOrderEntry(accessToken, orderRequest);
// API calls use trapi.raiaccept.com with Bearer token only
const orderResponse = await service.createOrderEntry(accessToken, orderRequest);
```

### Create Payment
### Token refresh and logout (merchant)

```typescript
const refreshed = await service.tokenRefresh(authResult.refreshToken, integrationContext);
await service.tokenLogout(authResult.refreshToken);
```

## Partner integration

For platform/partner integrations (e.g. Shopify apps) — requires mTLS client certificate.

```typescript
import { RaiAcceptService, HttpClient } from '@smartbase-js/raiaccept-api-client';
import { readFileSync } from 'fs';

// Initialize HTTP client (optional, for logging)
const httpClient = new HttpClient({
logger: console, // Optional: for debugging
});
const cert = readFileSync('/path/to/client.crt', 'utf-8');
const key = readFileSync('/path/to/client.key', 'utf-8');

// Initialize the unified SDK client
const service = new RaiAcceptService(httpClient);
const httpClient = new HttpClient({ logger: console });
const service = new RaiAcceptService(httpClient, cert, key);

// Authenticate
const authResult = await service.retrieveAccessTokenWithCredentials(
'your-username',
'your-password',
cert, // Client certificate for mTLS
key // Client private key for mTLS
'merchant-username',
'merchant-password',
integrationContext
);
const accessToken = authResult?.accessToken;
```

## Create payment (both modes)

// Create an order and payment session (two-step process)
```typescript
const orderRequest = {
invoice: {
amount: 100.00,
currency: 'EUR',
description: 'Test payment',
merchantOrderReference: 'ORDER-123',
items: [
{
description: 'Product 1',
numberOfItems: 1,
price: 100.00
}
]
items: [{ description: 'Product 1', numberOfItems: 1, price: 100.00 }],
},
urls: {
successUrl: 'https://example.com/success',
failUrl: 'https://example.com/fail',
cancelUrl: 'https://example.com/cancel',
notificationUrl: 'https://example.com/webhook'
notificationUrl: 'https://example.com/webhook',
},
consumer: {
email: 'customer@example.com',
firstName: 'John',
lastName: 'Doe',
phone: '+1234567890'
phone: '+1234567890',
},
paymentMethodPreference: 'CARD',
linkId: 'unique-link-id'
linkId: 'unique-link-id',
};

// Step 1: Create order entry
const orderResponse = await service.createOrderEntry(accessToken, orderRequest);
const orderIdentification = orderResponse.object.getOrderIdentification();
console.log('Order created:', orderIdentification);
const orderId = orderResponse.object.getOrderIdentification();

// Step 2: Create payment session for the order
const paymentSessionResponse = await service.createPaymentSession(
accessToken,
orderRequest,
orderIdentification
orderId
);

const paymentRedirectURL = paymentSessionResponse.object?.paymentRedirectURL;
console.log('Payment session created. Redirect customer to:', paymentRedirectURL);
console.log('Redirect to:', paymentSessionResponse.object?.paymentRedirectURL);
```

## API Reference

### Initialization

```typescript
import { RaiAcceptService, HttpClient } from '@smartbase-js/raiaccept-api-client';
// Merchant (default)
new RaiAcceptService(httpClient);

// With HTTP client (recommended for logging)
const httpClient = new HttpClient({ logger: console });
const client = new RaiAcceptService(httpClient);
// Partner (auto-detected when cert + key provided)
new RaiAcceptService(httpClient, cert, key);

// Without HTTP client (uses default)
const client = new RaiAcceptService();
// Explicit override
new RaiAcceptService(httpClient, cert, key, { authMode: 'partner' });
new RaiAcceptService(httpClient, cert, key, { authMode: 'merchant' });
```

### Authentication

```typescript
const authResult = await client.retrieveAccessTokenWithCredentials(
username,
password,
cert, // Client certificate for mTLS
key // Client private key for mTLS
);
const accessToken = authResult?.accessToken;
// Also available: authResult.refreshToken, authResult.accessTokenExpiresIn, authResult.refreshTokenExpiresIn
```
- `retrieveAccessTokenWithCredentials(username, password, integrationContext)`
- `tokenRefresh(refreshToken, integrationContext)`
- `tokenLogout(refreshToken)`

### Order Operations
### Order operations

- `client.createOrderEntry(accessToken, orderRequest)` - Create a new order
- `client.createPaymentSession(accessToken, sessionRequest, externalOrderId)` - Create payment session
- `client.getOrderDetails(accessToken, orderId)` - Get order details
- `client.getOrderTransactions(accessToken, orderId)` - Get order transactions
- `createOrderEntry(accessToken, orderRequest)`
- `createPaymentSession(accessToken, sessionRequest, externalOrderId)`
- `getOrderDetails(accessToken, orderId)`
- `getOrderTransactions(accessToken, orderId)`

### Transaction Operations
### Transaction operations

- `client.getTransactionDetails(accessToken, orderId, transactionId)` - Get transaction details
- `client.refund(accessToken, orderId, transactionId, refundRequest)` - Process a refund
- `getTransactionDetails(accessToken, orderId, transactionId)`
- `refund(accessToken, orderId, transactionId, refundRequest)`

### Utility Functions
### Utility functions

- `RaiAcceptService.transliterate(string)` - Transliterate non-Latin characters
- `RaiAcceptService.transliterateAndLimitLength(string, limit)` - Transliterate and limit length
- `RaiAcceptService.cleanPhoneNumber(phoneNumber)` - Clean phone number format
- `RaiAcceptService.getCountryIso3(countryCode)` - Convert 2-letter to 3-letter country code
Static helpers on `RaiAcceptService` for normalizing order/payment payload data:

## TypeScript Support
- `RaiAcceptService.transliterate(string)` — transliterate non-Latin characters to Latin
- `RaiAcceptService.transliterateAndLimitLength(string, limit?)` — transliterate and truncate (default limit 127)
- `RaiAcceptService.cleanPhoneNumber(phoneNumber)` — normalize phone number format (digits + leading `+`, max 15 chars)
- `RaiAcceptService.getCountryIso3(countryCode)` — convert 2-letter ISO country code to 3-letter
- `RaiAcceptService.getPaidStatuses()` / `getFailedStatuses()` / `getCancelledStatuses()` / `getRejectedStatuses()` — payment status groupings

This SDK is written in TypeScript and includes full type definitions. All types are exported and available for use in your TypeScript projects.
```typescript
RaiAcceptService.transliterate('Γεια σου'); // 'Geia sou'
RaiAcceptService.cleanPhoneNumber('+1 (234) 567-8900'); // '+12345678900'
RaiAcceptService.getCountryIso3('SK'); // 'SVK'
```

## Testing
## Migration from 0.9.x

Run the test suite:
Version 0.10.0 defaults to **merchant mode**. Partner integrations with cert + key work as in 0.9.x — mode is auto-detected. You may still pass `{ authMode: 'partner' }` explicitly.

```typescript
new RaiAcceptService(httpClient, cert, key);
```

See [CHANGELOG.md](./CHANGELOG.md) for details.

## Testing

```bash
# Run unit tests (mocked)
npm run unit-tests

# Run integration tests (real API calls!)
npm run integration-tests
npm run integration-tests:merchant
npm run integration-tests:partner
```

For more details, see [TEST_SETUP.md](./TEST_SETUP.md) and [tests/README.md](./tests/README.md).
See [TEST_SETUP.md](./TEST_SETUP.md) and [tests/README.md](./tests/README.md).

## License

OSL-3.0

Loading
Loading