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

# Cloud Agent Platform Integration

> Connect your users to Clink Wallet Service and complete Browser Pay purchases with encrypted credentials.

A cloud Agent platform connects each user to Clink, calls wallet and payment tools on that user's behalf, and completes checkout in its own browser. For Browser Pay credentials encrypted to your platform, use the [credential decryption example](/guides/agent/browser_pay/decryption).

## Prepare your platform connection

| Item | What to configure |
| :- | :- |
| OAuth client | Choose CIMD, pre-registration, or DCR in [MCP connection and OAuth](/guides/agent/mcp_integration). Reuse the client for the same application or deployment. |
| Environment | Use the corresponding MCP resource and OAuth endpoints consistently. Begin integration in UAT. |
| Redirect URI | Register the HTTPS callback that completes each user's connection. |
| Scopes | Enable the wallet and payment scopes below, plus any additional scopes required by the tools you use. |
| Browser Pay public key | Contact Clink offline to register your platform's RSA public key for the relevant environment. Provide a PEM public key with X.509 SubjectPublicKeyInfo content (`BEGIN PUBLIC KEY`). |

The Browser Pay flow needs these scopes:

```text theme={null}
wallet:read payment:execute instruction:read instruction:write events:read events:consume offline_access
```

`events:read` and `events:consume` support recovery after user actions. `offline_access` enables refresh tokens. Add `wallet:setup` if the platform changes a user's default card. The scopes registered for the OAuth client must include every scope requested by users. See the [tool references](/api-reference/mcp/browser_pay) for per-tool requirements.

<Note>
  OAuth client registration and Browser Pay public-key registration are separate steps. Submit the encryption public key through your Clink contact; it is not a DCR request parameter. Wallet queries do not require credential decryption.
</Note>

## Connect each user

Implement Authorization Code with PKCE (`S256`) using [the shared OAuth guide](/guides/agent/mcp_integration). Bind the authorization callback to the user who started the connection, and use that user's access token for their MCP requests. Maintain and refresh tokens separately for each user.

The OAuth connection grants access to Clink tools. A purchase authorization defines what the Agent can spend with a payment card. Connecting a user does not by itself authorize a purchase. When passkey verification is required, the platform presents the user action link and waits for completion. See [Wallet Service: Passkeys and purchase authorization](/guides/agent/wallet_service#passkeys-and-purchase-authorization).

The [Clink Skill](https://www.clinkbill.com/SKILL.md) installs a Host connection. For business operations, read the connected MCP server's current rules from `clink://skill/rules`; if resources are unavailable, call `get_skill_manifest` with `include_rules: true`. Follow the server's current rules when updating your integration.

## Run your first wallet call

After OAuth returns a user access token with `wallet:read`, use this read-only check to verify the connection. It discovers the tools and reads the wallet without starting a payment. The example uses the [official MCP TypeScript SDK v2](https://ts.sdk.modelcontextprotocol.io/v2/clients/connect).

<Accordion title="Node.js example: connect and read the wallet">
  Use Node.js 20.19 or later. In an example directory, install the client:

  ```bash theme={null}
  npm install @modelcontextprotocol/client@2
  ```

  Supply `CLINK_USER_ACCESS_TOKEN` through your runtime environment; it must belong to the connected user and the selected environment. `CLINK_MCP_URL` is optional and defaults to UAT. Save the following as `check-wallet.mjs`:

  ```javascript theme={null}
  import { Client, StreamableHTTPClientTransport } from "@modelcontextprotocol/client";

  const token = process.env.CLINK_USER_ACCESS_TOKEN;
  if (!token) throw new Error("Set CLINK_USER_ACCESS_TOKEN for the connected user.");

  const client = new Client({ name: "clink-wallet-check", version: "1.0.0" });
  const transport = new StreamableHTTPClientTransport(
    new URL(process.env.CLINK_MCP_URL ?? "https://uat-api.clinkbill.com/mcp"),
    { authProvider: { token: async () => token } }
  );

  try {
    await client.connect(transport);
    const { tools } = await client.listTools();
    if (!tools.some(tool => tool.name === "get_account_state")) {
      throw new Error("get_account_state is unavailable; check the MCP environment.");
    }

    const result = await client.callTool({ name: "get_account_state", arguments: {} });
    if (result.isError) throw new Error("Wallet read failed; check the token and scopes.");
    const account = result.structuredContent;
    if (!account || !Array.isArray(account.paymentMethods)) {
      throw new Error("Unexpected wallet response.");
    }
    console.log({ connected: true, walletReadable: true, cardCount: account.paymentMethods.length });
  } finally {
    try {
      await transport.terminateSession();
    } finally {
      await client.close();
    }
  }
  ```

  ```bash theme={null}
  node check-wallet.mjs
  ```
</Accordion>

Expected output is `connected: true`, `walletReadable: true`, and the current `cardCount`. A count of `0` is a successful wallet read with no cards, not a connection failure. For a long-running platform, use your per-user token refresh flow instead of the fixed token in this connection check.

## Complete a Browser Pay purchase

After the user connects through OAuth and requests a purchase, follow the checkout flow below. These diagrams show the encrypted-credential path with the platform public key already configured.

<Tabs>
  <Tab title="Payment flow">
    When a valid purchase authorization covers the payment, `get_credential` can return the credential directly.

    ```mermaid theme={null}
    %%{init: {"theme":"base","themeVariables":{"fontFamily":"inherit","actorBkg":"#F7F7F7","actorBorder":"#E7E7E7","actorTextColor":"#161616","actorLineColor":"#E7E7E7","signalColor":"#71717A","signalTextColor":"#3F3F46","noteBkgColor":"#F8E1CC","noteBorderColor":"#F8E1CC","noteTextColor":"#161616"},"sequence":{"width":116,"height":44,"actorMargin":64,"diagramMarginX":12,"diagramMarginY":12,"messageMargin":28,"noteMargin":14,"boxMargin":12,"wrap":false,"mirrorActors":false,"actorFontSize":14,"messageFontSize":14,"noteFontSize":14}}}%%
    sequenceDiagram
      participant M as Merchant
      participant P as Agent platform
      participant C as Clink MCP
      P->>M: Read final total
      M-->>P: Amount and currency
      P->>C: get_credential
      C-->>P: Encrypted credential + IDs
      Note over P: Decrypt card fields
      P->>M: Fill card and submit
      M-->>P: Payment result
      P->>C: confirm_result
    ```
  </Tab>

  <Tab title="When user action is required">
    If `get_credential` returns a `REDIRECT_USER` link, complete this flow, then return to the payment flow to use the credential.

    ```mermaid theme={null}
    %%{init: {"theme":"base","themeVariables":{"fontFamily":"inherit","actorBkg":"#F7F7F7","actorBorder":"#E7E7E7","actorTextColor":"#161616","actorLineColor":"#E7E7E7","signalColor":"#71717A","signalTextColor":"#3F3F46","noteBkgColor":"#F8E1CC","noteBorderColor":"#F8E1CC","noteTextColor":"#161616"},"sequence":{"width":116,"height":44,"actorMargin":64,"diagramMarginX":12,"diagramMarginY":12,"messageMargin":28,"noteMargin":14,"boxMargin":12,"wrap":false,"mirrorActors":false,"actorFontSize":14,"messageFontSize":14,"noteFontSize":14}}}%%
    sequenceDiagram
      participant U as User
      participant P as Agent platform
      participant C as Clink MCP
      C-->>P: REDIRECT_USER
      P-->>U: Show user action link
      U->>C: Complete card setup or approval
      P->>C: get_operation
      C-->>P: Setup complete
      P->>C: get_credential
      C-->>P: Credential + IDs
    ```

    Use `get_operation` for the returned setup operation. Once setup completes, call `get_credential` with the same checkout facts, without passing the setup operation ID. See [Browser Pay](/guides/agent/browser_pay) for other `SETUP_REQUIRED` cases.
  </Tab>
</Tabs>

Your platform needs to handle three handoffs:

* **User action:** preserve the checkout and setup Operation, show the returned link, and resume only after reading the updated state.
* **Payment credential:** use `credential.card` directly or apply the [decryption example](/guides/agent/browser_pay/decryption) to `key` and `payload`. Preserve the issuing Operation's payment identifiers before submission.
* **Merchant result:** operate the checkout browser and report the observed outcome. The complete amount, card-selection, and retry rules are in [Browser Pay](/guides/agent/browser_pay).

<Accordion title="Purchase and recovery orchestration">
  This pseudocode shows how the calls fit together. `callTool` represents an MCP call whose `isError` and structured output have been checked. Saving context, showing links, decryption, and merchant browser control are platform responsibilities, not additional Clink APIs.

  ```text theme={null}
  checkout = { merchantUrl, merchantName, amount, currency, paymentInstrumentId? }

  if resuming a saved setup operation:
    setup = callTool("get_operation", { operationId: setupOperationId, maxWaitSeconds: 15 })
    if setup.status != "SUCCEEDED":
      follow setup.next_action, or stop if the operation failed or expired
      return

  issued = callTool("get_credential", checkout)
  if issued.credential is absent:
    save checkout and issued.operation_id for recovery
    present issued.next_action to the user; do not open USER_DEVICE_ONLY links
    return

  reportIds = {
    operationId: issued.operation_id,
    orderId: issued.resources.payment_order_id,
    paymentExecutionDetailId: issued.resources.payment_execution_detail_id
  }
  save reportIds before filling the merchant form
  card = issued.credential.card, or decrypt issued.credential.key + payload
  if decryption fails or the final total changes:
    callTool("confirm_result", { ...reportIds, outcome: "NOT_SUBMITTED" })
    stop before submission

  fill the card fields, submit once, and inspect the merchant result
  outcome = "SUCCEEDED" | "FAILED" | "UNKNOWN", based on what was observed
  save the report arguments for retry
  callTool("confirm_result", { ...reportIds, outcome })
  if reporting fails: retry the saved report; do not submit payment again
  if outcome is "UNKNOWN": reconcile the existing payment before report_deadline
  ```

  Take checkout facts from the final merchant page: `amount` is in minor units, and `paymentInstrumentId` is included only when the user selected a card. For setup responses without a user link, follow the returned action as described in [Browser Pay](/guides/agent/browser_pay). After setup, keep the same checkout facts and selected card; do not pass the setup Operation ID to `get_credential`.

  Use payment identifiers from `resources`, or the corresponding credential payload fields. If they cannot be read, recover them from the issuing Operation before continuing. Include `paidAmount` and `currency` together when the merchant confirms the paid amount. See the [response examples](/api-reference/mcp/browser_pay) for the full shapes and report parameters.
</Accordion>

Clink provides the wallet, purchase authorization, payment credential, and result-reporting tools. Keep these completion points separate:

| Completed step | What it proves |
| :- | :- |
| Credential issued | Clink supplied a credential for this checkout. This does not prove merchant payment. |
| Merchant confirmed payment | The merchant page showed a successful payment; retain any observed merchant order reference. |
| Result recorded | Clink accepted the platform's report. It is not independent merchant confirmation. |

## Preserve the payment context

| Value | Purpose |
| :- | :- |
| `operation_id` | Identifies the Clink operation; use it for recovery and as `confirm_result.operationId`. |
| Original checkout facts | Let you resume the same checkout before a final result is reported. Include the selected `paymentInstrumentId` when applicable. |
| `orderId` and `paymentExecutionDetailId` | Identify the issued payment credential's order when reporting the result. Read them from the decrypted payload or the corresponding `resources` fields. |
| `next_action` and current revision | Tell you whether to redirect the user, wait, or invoke a specific next action. Read the latest operation before using a stale action. |

An `UNKNOWN` result means payment was submitted but the outcome could not be observed. Reconcile it through the same payment context and report the final result before the returned `report_deadline`; do not immediately start another payment. See [operation recovery](/api-reference/mcp/operations) and the [Browser Pay API](/api-reference/mcp/browser_pay).

## Validate the integration

Before rollout, verify these cases in the configured environment:

* Two users connect to the same OAuth client and each sees only their own wallet and operations.
* A valid purchase authorization returns a credential; a missing authorization produces the required user action and can be resumed.
* A response encrypted to the registered platform key decrypts using the example and produces payment fields usable in the merchant form.
* Success, failure, an unsubmitted payment, and an unknown result are reported with the correct identifiers.
* Returning from user authorization or recovering after a timeout continues the existing operation without blindly submitting another payment.

For the full purchase flow, continue to [Browser Pay](/guides/agent/browser_pay). For card selection and purchase authorization management, see [Wallet Service](/guides/agent/wallet_service).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.