CanopyAPI docs

Accept your first deposit

Go from a secret key to a settled payment in four steps.

  1. Get a secret key

    Every call below uses a secret key, cnpy_sk_live_.... Keep it on your server. Never send it to a browser.

    Canopy has two other credential types. See credentials for where each one can be used.

  2. Create a payment intent

    Call POST /api/v1/intents from your server. Create one intent for each user who is about to send funds.

    curl -X POST https://www.canopypay.io/api/v1/intents \
      -H "Authorization: Bearer cnpy_sk_live_a1b2c3_<64 hex chars>" \
      -H "Canopy-Version: 2026-09-01" \
      -H "Content-Type: application/json" \
      -d '{
        "merchantReference": "order_10024",
        "metadata": { "userId": "u_7781" }
      }'
    201 Createdjson
    {
      "intentId": "6f1b9c2e4d8a4f1b8c2e4d8a4f1b8c2e",
      "inboxAddress": "0x9f2a1c7b3e5d8a604c1f2b9e7d3a5c8b6e4f1d20",
      "created": true,
      "priceUnits": null,
      "oneTime": false,
      "widgetToken": "2f7a1d9c4b6e8035a1c7d3f6b8e04a2c5d7f9b1e3a6c8d0f2b4e6a8c0d2f4b6e"
    }

    This example has no destination field. The deposit settles to your account's own payout wallet.

    To send the funds to your user's wallet instead, see payout destinations. Two things must be turned on first:

    • the per-intent destinations setting on your account
    • a route that Canopy has switched to Dynamic mode
  3. Give your user a deposit address

    The response includes an inboxAddress. This is a deposit address for your user. They can send funds to it from any supported chain.

    For a checkout page instead, mount the widget with the response's intentId.

    The browser only needs that id. Canopy looks up the price, destination, fee and supported chains on its server. You do not need to fetch or pass anything else.

    If you use a bundler, install the package first:

    npm install @canopypay/checkout-sdk@0.7.2

    Then mount it. Or use a script tag and skip bundling:

    checkout.html
    <script src="https://canopypay.io/v1/canopy.js"></script>
    <script type="module">
      const { intentId } = await (
        await fetch("/my-server/create-canopy-intent")
      ).json();
    
      const handle = Canopy.mount({
        target: "#checkout",
        intentId,
        merchant: "cnpy_pk_live_abc123",
        onEvent: (e) => {
          if (e.type === "paid") showBanner("Payment sent");
        },
      });
    
      payButton.addEventListener("click", () => {
        handle.openNow(window.open("", "canopy_checkout", "width=460,height=640"));
      });
    </script>

    The npm build needs canopyOrigin. The script tag reads it from its own src. See the SDK reference for details.

    Open the popup synchronously, inside the click handler. If you await anything before the call, the browser blocks the popup. See popup timing.

    To show checkout inside your own page instead of a popup, use surface: "auto". You must register your page's origin first. See embed checkout inline.

  4. Watch for settlement

    Canopy confirms settlement with a webhook to your server, not in the browser. See webhooks for the events and how to verify signatures.

What's next

  • Payment intents lists every field you can send when creating an intent. It also covers the rule that each wallet can have only one active intent.
  • To set a different destination on each intent, see payout destinations. It lists the two settings that must be on first.
  • The API reference has an example request and response for every operation.
  • Credentials lists the three credential types and where each one can be used.