> ## Documentation Index
> Fetch the complete documentation index at: https://docs.augustus.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Treat the published Augustus OpenAPI specification (https://app.stainless.com/api/spec/documented/augustus/openapi.documented.yml) and the current API-reference pages as the source of truth for endpoints, request/response schemas, enum values, webhook event names, and required headers.
> Prefer the 2026-05-01 Banking API and @augustusbank/typescript-sdk for all new integrations. The 2023-01-01 API is a separate, older surface covering two products — Open Banking (instant bank transfer) checkout and refunds, and Manual Bank Transfer (MBT); use it only when one of those products is specifically required.
> Cite or link the relevant docs.augustus.com page when answering integration questions.
> Do not infer support for currencies, networks, scopes, account types, or operations that are not present in the current documentation.
> Use the sandbox base URL (https://api.sandbox.augustus.com) and placeholder credentials in examples. Never include or request a real API key.
> The Augustus docs MCP server (https://docs.augustus.com/mcp) provides documentation search and retrieval only; it does not execute authenticated Augustus API actions.

# Client integration

> Optimise your client integration of Augustus Checkout for the best user experience on any platform.

Recommended integration per platform:

* **Desktop web** — embed via the [React SDK](https://www.npmjs.com/package/@getivy/react-sdk) or an iframe.
* **Mobile web** — redirect to the Augustus-hosted checkout.
* **Mobile native** — open the Augustus-hosted checkout in the user's default browser; return via deep linking.

## Backend setup

Create a server-side endpoint that initiates a Checkout Session and returns the `redirectUrl` to your frontend.

```ts server/routes/checkout.ts theme={null}
import express from 'express'
import Ivy from '@getivy/node-sdk'

const router = express.Router()
const client = new Ivy()
router.post('/api/checkout', async (req, res) => {
  const session = await client.checkoutsession.create({
    referenceId: 'order_123',
    price: {
      total: req.body.amount,
      currency: req.body.currency || 'EUR',
    },
    locale: req.body.locale || 'en',
    successCallbackUrl: 'https://example.com/success',
    errorCallbackUrl: 'https://example.com/error',
    customer: {
      email: 'john.doe@example.com',
    },
  })

  res.json({ url: session.redirectUrl })
})

export default router
```

## Desktop web

Use the [React SDK](https://www.npmjs.com/package/@getivy/react-sdk) to embed the checkout in your page.

<Warning>
  * Embedded iframe: append `&iframe=true` to the checkout URL.
  * Modal iframe: append `&popup=true` to the checkout URL.

  The API doesn't include these parameters — you set them at render time. The React SDK does this automatically.
</Warning>

### React SDK

<Steps>
  <Step title="Install the SDK">
    ```bash theme={null}
    npm install @getivy/react-sdk
    ```
  </Step>

  <Step title="Create the checkout component">
    ```tsx components/IvyCheckout.tsx theme={null}
    import { IvyCheckout } from '@getivy/react-sdk'

    export function Checkout({
      amount,
      currency = 'EUR',
      locale = 'de',
      handleSuccess,
      handleCancel,
    }: {
      amount: number
      currency?: string
      locale?: string
      handleSuccess: (data: { redirectUrl: string; referenceId: string }) => void
      handleCancel: (data: { redirectUrl: string; referenceId: string }) => void
    }) {
      const response = await fetch('/api/checkout', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ amount, currency, locale }),
      })

      const { url } = await response.json()

      return (
        <IvyCheckout
          checkoutUrl={url}
          displayOptions={{ type: 'embedded' }}
          onSuccess={handleSuccess}
          onCancel={handleCancel}
        />
      )
    }
    ```

    <Tip>
      The React SDK automatically appends `&iframe=true` when using embedded mode.
    </Tip>
  </Step>

  <Step title="Add styling">
    ```css styles/ivy-checkout.css theme={null}
    @import "@getivy/react-sdk/dist/index.css";

    .ivy-embedded-checkout-screen {
      width: 100%;
      height: 100%;
      border: none;
    }

    .ivy-modal-content {
      position: fixed;
      inset: 0;
      z-index: 999999;
      display: flex;
      align-items: center;
      justify-content: center;
      background-color: rgba(10, 10, 10, 0.25);
    }

    .ivy-modal-content .ivy-modal-iframe-container {
      width: 100%;
      height: 100%;
      border-radius: 16px;
      overflow: hidden;
    }

    @media (max-width: 450px) {
      .ivy-modal-content .ivy-modal-iframe-container {
        border-radius: 0;
      }
    }
    ```
  </Step>
</Steps>

### Plain HTML (without the SDK)

If you can't use React, render the iframe directly. The iframe communicates with your page via [`postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage).

```html checkout.html theme={null}
<!DOCTYPE html>
<html>
  <body>
    <button onclick="startCheckout()">Pay with Augustus</button>
    <div id="iframe-container"></div>

    <script>
      async function startCheckout() {
        const response = await fetch('/api/checkout', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ locale: 'de' }),
        })

        const { url } = await response.json()
        const iframeUrl = url + '&iframe=true'

        document.getElementById('iframe-container').innerHTML = `
          <iframe
            src="${iframeUrl}"
            sandbox="allow-scripts allow-same-origin allow-popups allow-forms allow-popups-to-escape-sandbox allow-top-navigation"
            allow="clipboard-write"
            style="width:100%; height:650px; border:none; border-radius:8px;"
          ></iframe>
        `

        window.addEventListener('message', handleMessage)
      }

      function handleMessage(event) {
        try {
          const { source, type, value, referenceId } = JSON.parse(event.data)
          if (source !== 'ivy' || type !== 'iframe') return

          if (value === 'success') {
            // Handle success — referenceId matches your original.
          } else if (value === 'error') {
            // Handle failure or cancelation.
          }
        } catch (e) {
          // Ignore non-JSON messages
        }
      }
    </script>
  </body>
</html>
```

The iframe sends a `postMessage` with the following fields:

| Field         | Description                                                 |
| ------------- | ----------------------------------------------------------- |
| `source`      | Always `"ivy"`.                                             |
| `type`        | Always `"iframe"`.                                          |
| `value`       | Either `"success"` or `"error"`.                            |
| `referenceId` | Your original `referenceId` from Checkout Session creation. |

<Warning>
  The iframe `sandbox` attributes are required:

  * `allow-scripts` — required for the checkout to function.
  * `allow-same-origin` — enables secure communication.
  * `allow-forms` — required for payment form input.
  * `allow-popups`, `allow-popups-to-escape-sandbox` — required for bank redirects.
  * `allow-top-navigation` — required for completion redirects.
  * `allow="clipboard-write"` — required for copy-to-clipboard buttons.
</Warning>

## Mobile web

On mobile, redirect to the Augustus-hosted checkout. An iframe breaks the flow when the customer moves to and from their banking app.

```javascript theme={null}
function isMobile() {
  return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
}

async function startCheckout() {
  const response = await fetch('/api/checkout', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ amount: 100, currency: 'EUR' }),
  })

  const { url } = await response.json()

  if (isMobile()) {
    window.location.href = url
  } else {
    // Render the iframe on desktop — see above.
  }
}
```

Make sure the `successCallbackUrl` and `errorCallbackUrl` you pass to the Checkout Session point to pages on your site where the user lands after the bank flow completes.

## Mobile native

Open the checkout in the user's **default browser**. Do not use a WebView — it breaks bank authentication, deep linking, SSL, and session handling.

```javascript theme={null}
// Don't do this
<WebView source={{ uri: checkoutUrl }} />

// Do this instead
Linking.openURL(checkoutUrl)
```

### Open the checkout

<CodeGroup>
  ```javascript React Native theme={null}
  import { Linking } from 'react-native'

  const openCheckoutInBrowser = async () => {
    const response = await fetch('/api/checkout', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ amount: 100, currency: 'EUR' }),
    })

    const { url } = await response.json()

    if (await Linking.canOpenURL(url)) {
      await Linking.openURL(url)
    }
  }
  ```

  ```swift iOS (Swift) theme={null}
  import SafariServices

  func openCheckoutInBrowser() {
      guard let url = URL(string: checkoutUrl) else { return }
      let safariVC = SFSafariViewController(url: url)
      safariVC.delegate = self
      present(safariVC, animated: true)
  }
  ```

  ```kotlin Android (Kotlin) theme={null}
  fun openCheckoutInBrowser() {
      val intent = Intent(Intent.ACTION_VIEW, Uri.parse(checkoutUrl))
      intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
      startActivity(intent)
  }
  ```
</CodeGroup>

### Deep linking back to your app

Configure deep linking so the user returns to your app after payment:

```javascript theme={null}
import { Linking } from 'react-native'

useEffect(() => {
  const handleDeepLink = ({ url }) => {
    if (url.includes('payment-success')) {
      navigation.navigate('PaymentSuccess')
    } else if (url.includes('payment-error')) {
      navigation.navigate('PaymentError')
    }
  }

  const subscription = Linking.addEventListener('url', handleDeepLink)
  return () => subscription.remove()
}, [])
```

Configure your app's deep-linking scheme so the Augustus return URLs open your app.
