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

# Terms acceptance

> Present MoonPay's Terms of Use and Privacy Policy in your own UI, record acceptance with termsAcceptedAt, and capture the related consents on the API-driven path.

Present MoonPay's terms in your own UI. In the API-driven onboarding path there is no MoonPay-hosted terms screen: you display MoonPay's [Terms of Use](https://www.moonpay.com/legal/terms) and [Privacy Policy](https://www.moonpay.com/legal/privacy_policy), record the customer's explicit acceptance, and convey it to MoonPay when you create a session. This page covers the two ways to present the terms, how to record acceptance with `termsAcceptedAt`, and two more steps you own when you capture verification data in your own UI.

## When this applies

You present MoonPay's terms and record the customer's acceptance on two onboarding paths:

* **[Onboarding via API](/platform/guides/customer-api)**: you build the onboarding screens, so everything on this page applies.
* **[Guest checkout](/platform/guides/guest-checkout)**: the presentation rules are identical, and you convey acceptance with the same `termsAcceptedAt` field.

<Note>
  Terms acceptance is recorded against the customer, not per transaction. It is
  separate from the per-transaction payment disclosures you render at checkout.
  See [Going Live](/platform/overview/going-live) for those.
</Note>

## Choose a presentation method

Present MoonPay's terms in one of two ways. Pick one at integration time; don't mix them.

* **Reference**: your terms of service include a required language block that links to MoonPay's Terms of Use and states that MoonPay provides the regulated services. One accept control covers both. Your MoonPay account team provides the exact text.
* **Side by side**: you show MoonPay's current Terms of Use in full, unedited, next to your own terms, with a clear boundary between the two. One acceptance covers both.

### Rendering rules

Whichever method you choose, the same rules apply:

* The terms must be visible without any interaction. Do not hide them behind tooltips, expandable menus, or secondary screens.
* Link to the canonical URLs as tappable hyperlinks. Never inline their contents into your own copy: MoonPay updates these documents over time, and a copied snapshot goes stale.
* Capture the timestamp at the moment the customer explicitly accepts, not when the screen renders or when you create the session.

| Document       | Canonical URL                                                                                 |
| -------------- | --------------------------------------------------------------------------------------------- |
| Terms of Use   | [https://www.moonpay.com/legal/terms](https://www.moonpay.com/legal/terms)                    |
| Privacy Policy | [https://www.moonpay.com/legal/privacy\_policy](https://www.moonpay.com/legal/privacy_policy) |

## Record the acceptance

Capture the timestamp when the customer accepts, and pass it as `termsAcceptedAt` (ISO 8601) when you create the session with `POST /platform/v1/sessions`.

<CodeGroup>
  ```ts Create session with terms acceptance theme={null}
  const url = "https://api.moonpay.com/platform/v1/sessions";

  const res = await fetch(url, {
    headers: {
      "Content-Type": "application/json",
      "X-Api-Key": "sk_test_123",
    },
    method: "POST",
    body: JSON.stringify({
      externalCustomerId: "your_user_id",
      deviceIp: "...ip address from client",
      termsAcceptedAt: "2026-07-17T09:41:12Z", // ISO 8601, within 60s ahead of server time
    }),
  });

  console.log(await res.json());
  ```

  ```json Result theme={null}
  {
    "sessionToken": "c3N0XzAwMQ=="
  }
  ```
</CodeGroup>

`termsAcceptedAt` can be at most 60 seconds ahead of server time; there is no past limit. MoonPay records the terms version that was live at that timestamp and binds the acceptance to the customer when the session is authorized. A timestamp outside the allowed range returns a 400 with the code `terms_accepted_at_out_of_range`.

Re-sending `termsAcceptedAt` for a customer who has already accepted the current version is safe: the attestation is idempotent. When in doubt, send it.

The attestation records what you assert: that this customer explicitly accepted MoonPay's terms at that moment. You remain responsible for the authenticity of the acceptance, and you keep your own acceptance records available to MoonPay on request.

<Note>
  Attestations are scoped to the API key's environment. If the customer
  transacts in both sandbox and live, record their acceptance in both.
</Note>

<Callout icon="book" iconType="regular">
  See the [sessions API
  reference](/api-reference/platform/endpoints/sessions/create) for all fields
  and error responses.
</Callout>

## Handle `termsAcceptanceRequired`

Until a valid attestation exists for the current terms version, the customer can't transact. The `termsAcceptanceRequired` status surfaces with no credentials attached, from both the connection check ([web](/platform/sdk-reference/web/get-connection#connection), [React Native](/platform/sdk-reference/react-native/get-connection#connection)) and the [Auth frame](/platform/frames/auth). The `skipKyc` option never suppresses it: legal requirements can't be skipped.

To recover:

1. Re-present the terms with the presentation method you chose.
2. Capture a fresh acceptance timestamp.
3. Create a new session with `termsAcceptedAt`.
4. Relaunch the flow.

Passing `termsAcceptedAt` requires the Identity or Guest Checkout account capability.

## Re-present the terms when they change

Two events require a fresh acceptance:

* **MoonPay materially updates its terms.** `termsAcceptanceRequired` reappears on the connection check. Run the same recovery: re-present the terms, capture a fresh timestamp, create a new session with `termsAcceptedAt`, and relaunch the flow.
* **Your own terms materially change (reference method).** MoonPay sends no signal, because the reference lives in your terms of service. Re-present the terms and send a fresh `termsAcceptedAt` yourself.

## Before you submit customer data

Capturing verification data in your own UI comes with two more steps: a consent you display and a verification you perform.

### Biometric consent for selfie and document images

If your integration captures selfie or identity-document images, display a biometric consent disclosure to the customer before you submit any images through the [file-upload flow](/platform/guides/customer-api#upload-a-file). Contact your MoonPay account team for the required disclosure text.

### Verify phone numbers before you submit them

Verify that the customer owns the phone number with a one-time passcode before you submit it, and re-verify at least once every 30 days. MoonPay does not independently re-verify the number: submitting it is your attestation that verification occurred. See [KYC data requirements](/platform/guides/kyc-data-requirements) for the format rules.

## Next steps

<CardGroup cols={3}>
  <Card title="Onboarding via API" href="/platform/guides/customer-api">
    Check KYC status, submit outstanding requirements, and handle verification
    in your own UI.
  </Card>

  <Card title="Guest checkout" href="/platform/guides/guest-checkout">
    Let new customers buy with Apple Pay; the same `termsAcceptedAt` field
    records their acceptance.
  </Card>

  <Card title="Going Live" href="/platform/overview/going-live">
    The acceptance criteria you meet before production, including
    per-transaction payment disclosures.
  </Card>
</CardGroup>
