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

# Migrating from invoices to payment requests

In 2026, CryptoProcessing introduced [payment requests](/payment-requests) — a new payment link implementation that aims at replacing the older Invoices feature. It provides a similar customer experience, while introducing some new features.

This page showcases the main changes that you need to make in your API integration when switching from invoices to payment requests. You can also use the [Migration checklist](#migration-checklist) to make sure you adapted to the payment requests API.

## New endpoint, same authentication

To create a payment request, use the new [/payments/v1/requests](/api-reference/endpoints/payments) endpoint. The [authentication mechanism](/api-reference/authentication) is the same as for **/v2/invoices/create**.

<Card horizontal icon="angles-right" title="See the full API endpoint documentation" href="/api-reference/endpoints/payments">
  Learn the new parameters and see a full request example
</Card>

## Currencies with networks

The way the currencies are represented in the payment requests API is different from the invoices API. Each field is now an object, not a plain string.

* Inside [currency](/api-reference/endpoints/payments#body-currency), set **iso** to the code of the currency you want to receive. If it is a cryptocurrency, also specify the **network\_name**.

* Inside the optional [payment\_currency](/api-reference/endpoints/payments#body-payment-currency), set **iso** to the code of the cryptocurrency you want the customer to pay. You may also specify the **network\_name** — or omit it and let the customer choose the network themselves.

Note that unlike the invoices' **sender\_currency** parameter, [payment\_currency](/api-reference/endpoints/payments#body-payment-currency) does not affect the timer behavior. For most merchants, we recommend omitting this parameter and letting the customer choose the currency themselves. This both simplifies the implementation on your side and ensures that customers can choose from all supported currencies and networks, with new ones added automatically in the future. If necessary, you can limit the available currencies in the [payment currency settings](/payment-requests/currencies).

<Columns cols={2}>
  ```json title="Invoice" theme={null}
  "currency": "EUR",
  "sender_currency": "USDC",
  ```

  ```json title="Payment request" theme={null}
  "currency": {
    "iso": "EUR"
  },
  "payment_currency": {
    "iso": "USDC",
    "network_name": "ethereum"
  },
  ```
</Columns>

<Card horizontal icon="angles-right" title="See the currency codes for payment requests" href="/api-reference/currency-codes#currency-codes-for-payment-requests">
  Learn the ISO codes and available network names for the API calls
</Card>

## Flexible payment lifetime

Unlike invoices, which offer either a fixed 15-minute timer or unlimited time, payment requests let you configure the lifetime to fit your business needs.

<table>
  <thead><tr><th>Invoice</th><th /><th>Payment request</th></tr></thead>

  <tbody>
    <tr>
      <td>
        Either **15 minutes** or **unlimited time** <br />
        to choose the currency
      </td>

      <td>
        →
      </td>

      <td>
        Between **5 minutes** and **60 days** <br />
        as the overall lifespan
      </td>
    </tr>

    <tr>
      <td>
        **Up to 15 minutes** <br />
        for the transactions to be created <br /><br />
        **+ 24 hours** <br />
        for the transactions to be confirmed
      </td>

      <td>
        →
      </td>

      <td>
        **Up to 1 hour** <br />
        for the transactions to be created and confirmed <br />
        (cannot exceed the lifespan)
      </td>
    </tr>
  </tbody>
</table>

<Columns>
  ```json title="Invoice" theme={null}
  "timer": true,
  ```

  ```json title="Payment request" theme={null}
  "life_time_duration": 3600,
  ```
</Columns>

If the customer pays in a different currency than the one you requested, CryptoProcessing locks the conversion rate for up to 1 hour. This is similar to an invoice's second 15-minute timer. The customer's transaction must be both created and confirmed within this period, or the payment request expires.

Note that the rate lock timer never exceeds the overall lifespan of the payment request. For example, if you set [life\_time\_duration](/api-reference/endpoints/payments#body-life-time-duration-one-of-0) to 30 minutes, and it took 5 minutes for the customer to open the link and select the payment currency, they will only have 25 minutes (not 1 hour) left to pay it.

Once the payment request expires, any new transaction will be marked as [late\_payment](/api-reference/callbacks/payment-request-callbacks#body-transactions-items-late-payment) and can be subject to an [automatic refund](/payment-requests/refunds).

<Card horizontal icon="angles-right" title="Read more about the payment request timers" href="/payment-requests#lifespan-and-rate-lock">
  Learn how **lifespan** and **rate\_mode** fields affect the payment request behavior
</Card>

## Two modes of currency pre-selection

For a payment request with both the currency and the network pre-selected, the new [rate\_mode](/api-reference/endpoints/payments#body-rate-mode) parameter determines what the customer sees on the page.

* **Standard mode** (the default): the customer still sees a page that describes the requested amount, the conversion rate, the processing fee (if you [pass the fees to the customer](/payment-requests/fees#passing-the-processing-fee-to-your-customer)), and the total amount to pay. On the same page, the customer is asked to enter their email address and [KYC data](/user-data-collection) (unless you provided it yourself).

* **Fixed mode**: the customer skips the first step entirely and goes straight to the payment details. The customer's email address and the [KYC data](/user-data-collection) must be provided by you when creating the payment request. This is the closest equivalent of an invoice with **timer** and **sender\_currency**.

  The lifespan of a fixed payment request never exceeds 1 hour, because the rate lock timer starts immediately after creation.

  A fixed payment request generates a crypto address immediately, before any interaction with the customer. If you want to show it to the customer in your own interface, you can find it as [payment\_details.address](/api-reference/endpoints/payments#response-data-payment-details-address) in the API response.

<Columns cols={2}>
  ```json title="Invoice" theme={null}
  "timer": true,
  "sender_currency": "USDC",
  ```

  ```json title="Payment request" theme={null}
  "rate_mode": "fixed",
  "payment_currency": {
    "iso": "USDC",
    "network_name": "ethereum"
  },
  ```
</Columns>

If you previously used invoices with a pre-selected currency, the fixed mode lets you keep your current flow, where the customer chooses the currency and the network on your side. However, we still recommend the standard mode, which automatically supports newly added currencies and networks. If necessary, you can limit the currencies customers can pay with in the [payment currency settings](/payment-requests/currencies).

<Card horizontal icon="angles-right" title="Read more about fixed payment requests" href="/payment-requests/fixed-payment-requests">
  Learn how to skip the currency selection step for the customer
</Card>

## Underpayment tolerance

By default, CryptoProcessing always expects a customer to send the full requested amount of funds, and failing to do so triggers the [automatic refund](/payment-requests/refunds) mechanism. If you used to allow *partial pay* in your invoices (by setting **type** to “good\_until\_expired”), you may want to change the default behavior.

To do so, configure a custom underpayment tolerance in your merchant settings. This will let you accept payments that are less than requested by a specific amount. Setting the tolerance to 100% would be an equivalent to applying the *partial pay* mode to all your payment requests.

<Card horizontal icon="angles-right" title="Read more about underpayment handling" href="/payment-requests/underpayments">
  Learn how to set up an underpayment tolerance for payment requests
</Card>

## Other changes

* A payment request doesn't have a **title** but may still have a [description](/api-reference/endpoints/payments#body-description). Similar to an invoice, the customer can find the description in the “Payment details” dialog on the payment page.

* The payment request API accepts [url\_store](/api-reference/endpoints/payments#body-url-store) — a link that, if provided, will be displayed under the payment form as “Return to merchant”. See [Backlinks](/payment-requests/backlinks).

* Unlike an invoice, a payment request cannot be canceled until either the payment arrives or [the timer expires](/payment-requests#lifespan-and-rate-lock).

* There is an option to [pass the processing fees to the customer](/payment-requests/fees#passing-the-processing-fee-to-your-customer).

* There is an option to [limit the currencies available to customers](/payment-requests/currencies).

## Migration checklist

<AccordionGroup>
  <Accordion title="Request" defaultOpen>
    * [currency](/api-reference/endpoints/payments#body-currency): pass an object using [the new notation](#currencies-with-networks).
    * **sender\_currency** → [payment\_currency](/api-reference/endpoints/payments#body-payment-currency), pass an object using [the new notation](#currencies-with-networks).
    * **type**: remove. To accept partial payments, configure [underpayment tolerance](#underpayment-tolerance) in your merchant settings.
    * **timer** → [life\_time\_duration](/api-reference/endpoints/payments#body-life-time-duration-one-of-0) or [life\_time\_date\_time](/api-reference/endpoints/payments#body-life-time-date-time-one-of-0). See [Flexible payment lifetime](#flexible-payment-lifetime).
    * **title**: remove.
    * **email\_user** → [end\_user\_email](/api-reference/endpoints/payments#body-end-user-email)
  </Accordion>

  <Accordion title="Response">
    * [id](/api-reference/endpoints/payments#response-data-id): make sure to expect a UUID instead of a number.
    * **url** → [payment\_link](/api-reference/endpoints/payments#response-data-payment-link)
    * **address** → [payment\_details.address.value](/api-reference/endpoints/payments#response-data-payment-details-address-value)
    * **tag** → [payment\_details.address.tag](/api-reference/endpoints/payments#response-data-payment-details-address-tag)
    * **title**: removed.
    * [status](/api-reference/endpoints/payments#response-data-status): process according to [payment request statuses](/payment-requests/statuses).
    * [currency](/api-reference/endpoints/payments#response-data-currency): process according to [the new notation](#currencies-with-networks).
    * **sender\_currency** → [payment\_currency](/api-reference/endpoints/payments#response-data-payment-currency), process according to [the new notation](#currencies-with-networks).
    * **sender\_amount** → [payment\_details.expected\_amount](/api-reference/endpoints/payments#response-data-payment-details-expected-amount)
    * **fixed\_at**: removed.
    * **release\_at** → [life\_time](/api-reference/endpoints/payments#response-data-life-time) or [valid\_until](/api-reference/endpoints/payments#response-data-valid-until). See [Flexible payment lifetime](#flexible-payment-lifetime).
    * **seconds\_left**: removed.
  </Accordion>

  <Accordion title="Callback">
    * **id** → [payment\_request\_id](/api-reference/callbacks/payment-request-callbacks#body-payment-request-id)
    * [type](/api-reference/callbacks/payment-request-callbacks#body-type): now always equals to “payment\_request”.
    * [currency\_received.currency](/api-reference/callbacks/payment-request-callbacks#body-currency-received-currency): process according to [the new notation](#currencies-with-networks).
    * [transactions\[\]](/api-reference/callbacks/payment-request-callbacks#body-transactions): some fields were changed or removed. Make sure to expect [the new currency notation](#currencies-with-networks) in [currency](/api-reference/callbacks/payment-request-callbacks#body-transactions-items-currency) and use [status](/api-reference/callbacks/payment-request-callbacks#body-transactions-items-status) instead of **confirmations**.
    * [fees\[\].currency](/api-reference/callbacks/payment-request-callbacks#body-fees-items-currency): process according to [the new notation](#currencies-with-networks).
    * **error** → [status\_reason](/api-reference/callbacks/payment-request-callbacks#body-status-reason)
    * [status](/api-reference/callbacks/payment-request-callbacks#body-status): process according to [payment request statuses](/payment-requests/statuses).
    * **crypto\_address** → [payment\_request\_address](/api-reference/callbacks/payment-request-callbacks#body-payment-request-address): some fields were changed. Make sure to expect a UUID as the **id** and [the new currency notation](#currencies-with-networks) in **currency** and **convert\_to**.
    * [currency\_sent.currency](/api-reference/callbacks/payment-request-callbacks#body-currency-sent-currency): process according to [the new notation](#currencies-with-networks).
    * **currency\_sent.amount** → [currency\_sent.received\_amount](/api-reference/callbacks/payment-request-callbacks#body-currency-sent-received-amount)
  </Accordion>
</AccordionGroup>

<Card horizontal icon="angles-right" title="Read the full API endpoint documentation" href="/api-reference/endpoints/payments">
  /payments/v1/requests
</Card>

<Card horizontal icon="angles-right" title="Read the full API callback documentation" href="/api-reference/callbacks/payment-request-callbacks">
  payment\_request
</Card>


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