# Configuration

ODUS Elements is configured at two levels:

* **Global** — via the `ElementsConfig` object passed to the `OdusElements` constructor.
* **Per-element** — via `MountOptions` passed to `update()` after mounting individual elements.

## ElementsConfig

| Option                     | Type                                                    | Required | Description                                                                  |
| -------------------------- | ------------------------------------------------------- | -------- | ---------------------------------------------------------------------------- |
| `apiKey`                   | string                                                  | ✅       | Required, but not used since version 0.14.0 of the SDK. Pass `'pk_retired'`. |
| `environment`              | `'test'` \| `'live'`                                    | ✅       | API environment                                                              |
| `returnUrl`                | string                                                  | ✅       | URL to redirect to after 3DS authentication or other redirect flows          |
| `locale`                   | [Locale](#localization)                                 |          | Language for all elements (auto-detected by default)                         |
| `callbacks`                | [Callbacks](#callbacks)                                 |          | Payment lifecycle event handlers                                             |
| `additionalPaymentMethods` | [AdditionalPaymentMethods](#additional-payment-methods) |          | Express payment method config (e.g., Apple Pay)                              |

```
const checkout = new OdusElements({

  apiKey: 'pk_retired',

  environment: 'test',

  returnUrl: 'https://your-website.com/checkout/return',

  locale: 'en',

  callbacks: {

    onPaymentSucceeded: (result) => console.log('Succeeded', result),

    onPaymentFailed: (error) => console.error('Failed', error),

    onActionRequired: (url) => {

      window.location.href = url;

    },

  },

});
```

## Callbacks

Handle payment lifecycle events by passing callback functions in the `callbacks` option.

Updating Callbacks After Initialization

In reactive frameworks (React, Vue, Svelte), callbacks defined at mount time capture state via closure and can become stale when dependencies change. Use `setCallbacks()` to update callbacks without remounting:

```
// React example

useEffect(() => {

  checkoutRef.current?.setCallbacks({

    onPaymentSucceeded: () => trackPurchase(priceId, quantity),

    onPaymentFailed: (result) => logError(priceId, result),

  });

}, [priceId, quantity]);
```

Only the callbacks you pass are replaced — omitted callbacks remain unchanged.

### onPaymentSucceeded

Fires when a payment is successfully authorized. Does **not** fire for redirect-based flows (PayPal, 3DS).

```
onPaymentSucceeded: (result) => {

  // result is the payment status: 'authorized'

  window.location.href = '/checkout/success';

};
```

### onPaymentFailed

Fires when a payment fails. Does **not** fire for redirect-based flows.

```
onPaymentFailed: (result) => {

  // result is a user-friendly error message

  console.error('Payment failed:', result);

};
```

### onActionRequired

Fires when a payment requires a redirect (e.g., 3DS authentication, PayPal authorization).

```
onActionRequired: (redirectUrl) => {

  window.location.href = redirectUrl;

};
```

info

Unlike Drop-in Checkout, Elements has no `manualActionHandling` toggle — `onActionRequired` always fires when a redirect is needed. Handle the URL however you like (navigate, open in a modal, etc.).

### onLoadingStateChange

Fires when the loading state changes while a payment is being authorized — `true` when the request starts and `false` when it settles. Use it to show or hide your own loading indicator.

```
onLoadingStateChange: (isLoading) => {

  if (isLoading) {

    // Show loading spinner, disable the pay button

  } else {

    // Hide loading spinner, re-enable the pay button

  }

};
```

## Localization

Elements auto-detects the customer's browser language by default. Override this globally in `ElementsConfig`:

```
const checkout = new OdusElements({

  // ...other options

  locale: 'fr',

});
```

### Supported Locales

| Code | Language   |
| ---- | ---------- |
| `en` | English    |
| `fr` | French     |
| `de` | German     |
| `es` | Spanish    |
| `it` | Italian    |
| `pl` | Polish     |
| `pt` | Portuguese |
| `tr` | Turkish    |
| `cs` | Czech      |
| `nl` | Dutch      |
| `sk` | Slovak     |

## Additional Payment Methods

Configure express payment methods through the `additionalPaymentMethods` option.

### Apple Pay

```
const checkout = new OdusElements({

  // ...other options

  additionalPaymentMethods: {

    applePay: {

      displayName: 'My Store',

      countries: ['US', 'GB'],

      requiredBillingContactFields: ['postalAddress'],

      requiredShippingContactFields: ['email', 'name'],

    },

  },

});
```

| Option                          | Type                    | Description                                                                                                                                                                                                                                        |
| ------------------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `displayName`                   | string                  | Name shown in the Apple Pay payment sheet                                                                                                                                                                                                          |
| `countries`                     | string\[]               | ISO 3166-1 alpha-2 country codes where Apple Pay is available, matched case-insensitively. Omit it, or pass an empty array, to offer Apple Pay everywhere. When the list is non-empty the button stays hidden until the shopper's country is known |
| `requiredBillingContactFields`  | ApplePayContactField\[] | Billing fields to request ([Apple docs](https://developer.apple.com/documentation/applepayontheweb/applepaypaymentrequest/requiredbillingcontactfields))                                                                                           |
| `requiredShippingContactFields` | ApplePayContactField\[] | Shipping fields to request ([Apple docs](https://developer.apple.com/documentation/applepayontheweb/applepaypaymentrequest/requiredshippingcontactfields))                                                                                         |

**ApplePayContactField values:** `email`, `name`, `phone`, `postalAddress`, `phoneticName`

note

PayPal requires no additional configuration — simply mount the `express.payPal` element and it renders automatically after `associatePayment()` is called, provided the payment supports PayPal.

## Per-Element Options (MountOptions)

Customize individual elements via `update()` after mounting:

```
checkout.elements.contact.email.mount('#email-container');

checkout.elements.contact.email.update({

  locale: 'fr',

  disabled: true,

  initialValue: 'user@example.com',

});
```

```
// Limit street address to 100 characters

checkout.elements.address.street.mount('#street-container');

checkout.elements.address.street.update({ maxLength: 100 });
```

```
// Override the label and placeholder to match your existing checkout copy

checkout.elements.address.street.update({

  label: 'Street Address',

  placeholder: 'e.g. 123 Main St',

});
```

| Option         | Type    | Description                                                                                                                  |
| -------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `locale`       | string  | Override the global locale for this element                                                                                  |
| `disabled`     | boolean | Render the element in a disabled state                                                                                       |
| `initialValue` | varies  | Pre-fill the element (type depends on the element)                                                                           |
| `maxLength`    | number  | Maximum character limit for text inputs (e.g., `address.street`)                                                             |
| `label`        | string  | Override the field label. Applies to text elements (address, cardholder, email, phone). Defaults to the localized copy       |
| `placeholder`  | string  | Override the field placeholder. Applies to text elements (address, cardholder, email, phone). Defaults to the localized copy |
| `callbacks`    | object  | Per-element event callbacks                                                                                                  |

### Per-Element Events

Register event callbacks using `on()`:

```
checkout.elements.contact.email.on('change', (data) => console.log('changed', data)).on('blur', () => console.log('blurred'));
```

| Event    | Description                                   |
| -------- | --------------------------------------------- |
| `change` | Element value changed                         |
| `blur`   | Element lost focus                            |
| `focus`  | Element gained focus                          |
| `error`  | Element encountered a validation error        |
| `ready`  | Element finished rendering and is interactive |
