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

# Invoice issue

> Additional parameters can be transferred in the request, for example:

* `description` – invoice description,
* `phone` – phone number linked to the wallet;
* `account` – card number;

The list of these parameters depends on the payway (`payway`). The required additional parameters for the payway can be found in the request "Getting payment methods for input" [shop_input_config/shop](/api-reference/invoice-create/getting-payment-methods-for-input) in the `add_ons_config` response field.

### Redirecting to invoice payment forms

If the request is successful, API will return the parameters necessary to redirect the user to the payment system for payment. These parameters will be in the `data` field of the response. The `data.data` field contains the parameters to be transferred during redirection (in the form of `GET` or `POST` request parameters).

The redirection method depends on the `method` parameter. The generated request must be sent to the URL specified in the `url` field of the `data` field.

For example, if you receive a `POST` in the `method` parameter to redirect a client to pay an invoice, you need to generate an HTML form from the parameters received in the response body (these parameters will differ for different payment systems).

An example of forming an HTML form using the `jinja2` template language:

```jinja2
<form method="POST" action="{{ data['url'] }}">
    {% for param, value in data['data'].items() %}
      <input name="{{ param }}" value="{{ value }}" />
    {% endfor %}
</form>
```

For the data specified in the example response below, the following HTML form will be obtained:

```html
<form method="POST" action="https://test-checkout.domain.com/form/">
  <input name="transaction_id" value="a1b2c3" />
  <input name="payment_type" value="card" />
  <input name="fail_url" value="https://metaexamplesite.com/payment/?status=fail" />
  <input name="success_url" value="https://metaexamplesite.com/payment/?status=success" />
  <input type="submit" />
</form>
```

In case of `"method": "GET"` it is required to perform HTTP redirect to the URL with the parameters (using [percent‐encoding](https://en.wikipedia.org/wiki/Percent-encoding)), received in the `data.data` response field.

The URL is generated according to the following algorithm:

```python
import urllib.parse
redirect_url = '{url}?{parameters}'.format(url=data['url'], parameters=urllib.parse.urlencode(data['data']))
```

An example of the formed URL: `https://test-checkout.domain.com/form/?transaction_id=a1b2c3&payment_type=card&fail_url=https%3A%2F%2Fmetaexamplesite.com%2Fpayment%2F%3Fstatus%3Dfail&success_url=https%3A%2F%2Fmetaexamplesite.com%2Fpayment%2F%3Fstatus%3Dsuccess`

<div class="attention">
Please note that the parameters <code>failed_url</code>, <code>success_url</code>, <code>callback_url</code>, <code>callback_rejected_url</code> specified in the shop settings have priority over those specified in request. If you want to use unique url for each request, you need to inform the manager about it.
</div>

### Payer Browser Authentication for 3D Secure

For 3ds 2.0 payments with card data to be successful, the payer's browser information must be collected.

You can collect the data yourself or let our service perform this for you. If you collect the data on your end, please ensure that all the necessary values are included to the payment initiation request [/invoice/create](/api-reference/invoice-create/invoice-issue).

As an example, the provided JavaScript code could be employed to obtain the Payer Browser information. Please be aware that the `client_info` fields provided below do not include `browser_accept_header`.

```js
let client_info = {
    "browser_java_enabled": window.navigator.javaEnabled(),
    "browser_javascript_enabled": true,
    "browser_language": window.navigator.language,
    "browser_color_depth": window.screen.colorDepth.toString(),
    "browser_screen_height": window.screen.height.toString(),
    "browser_screen_width": window.screen.width.toString(),
    "browser_tz": (new Date()).getTimezoneOffset().toString(),
    "browser_user_agent": window.navigator.userAgent,
    "challenge_window_size": "05"
}
```

If the payer's browser data is not provided in the [/invoice/create](/api-reference/invoice-create/invoice-issue) request, it will be necessary to redirect the payer to our service as an intermediate step using a `data` object, so that our service can collect the necessary browser data. See [Redirecting to invoice payment forms](#redirecting-to-invoice-payment-forms) for the details on redirect.

<div class="success">
<p>Fields involved in request signature generation:</p>

* `amount`
* `currency`
* `payway`
* `shop_id`
* `shop_order_id`
</div>




## OpenAPI

````yaml /openapi.yaml post /invoice/create
openapi: 3.0.2
info:
  version: 1.0.0
  title: M4 Payment Gateway API
  termsOfService: https://m4solutions.io/terms
  contact:
    url: https://api.m4psp.com/gateway/v1/
    name: M4 Support
  description: >-
    ![M4 Logo](/assets/m4/images/m4-logo.png)


    ## Description


    Using this API, you can interact with M4 payment platform: accept payments,
    make payments and perform other operations supported by the platform.


    API runs over HTTP(S) protocol and uses JSON format to exchange data.


    All API requests must use `UTF-8` encoding and specify the `Content-Type:
    application/json` header. Each request must be signed, the signature
    generation process is described below, in the **Request signature** section.


    We use the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) standard as
    the date and time formats, if the time zone is not specified, then
    [UTC+03:00](https://en.wikipedia.org/wiki/Time_zone) is assumed.



    ## API changes


    To ensure that our API improvements do not break your integration, please
    consider the following list of backward compatible changes that can occur
    without increasing your M4 API version number.


    <div class="success">

    <p>We consider the following changes to our services to be
    backward-compatible:</p>


    * Adding new optional request parameters to existing API methods

    * Adding new fields to existing API responses (disregarding nullability)

    * Changing the order of fields in existing API responses

    * Adding new error codes

    * Adding new optional HTTP request headers

    * Adding new HTTP response headers

    * Adding new types of callback notifications

    * Changing the order of fields in callback notifications

    * Adding new fields in callback notification (while complying with the
    request signing rules)

    </div>


    ## Request signature


    <SecurityDefinitions />
servers:
  - url: https://api.m4psp.com/gateway/v1/
    description: The production API server
  - url: https://api.test.cplus-int.tech/gateway/v1/
    description: The test API server
security: []
tags:
  - name: invoice-create
    x-displayName: Invoice issue (payment creation)
    description: >
      ### Invoicing procedure


      `Single-step payment` is a type of payment in which a single request
      [invoice/create](/api-reference/invoice-create/invoice-issue) is
      immediately blocking and withdrawing funds.


      `Two-step payment` is a type of payment when funds are withdrawn in two
      steps.

      *You can check which payment ways support two-stage payment with the
      manager.*

      The first request
      [invoice/hold](/api-reference/invoice-create/funds-hold-two-stage-payments)
      is used to hold (block) funds on the client's account.

      The second request
      [invoice/charge](/api-reference/invoice-create/confirmation-of-funds-withdrawal-charge)
      initiates the withdrawal.

      If you want to cancel a previously held payment, then cancel it using the
      [invoice/unhold](/api-reference/invoice-create/cancellation-of-funds-holding)
      method. The money will be returned to the payer.


      ### Single-step payment

      ![Invoice Flow Diagram](assets/common/images/en/invoice-flow.v1.png)


      1. User generates an order on the shop's website;


      2. Shop sends a request to pre-calculate the invoice and get additional
      parameters
      [invoice/try](/api-reference/invoice-create/invoice-preliminary-calculation);


      3. When receiving `result: true`, verify the availability of additional
      information in `add_ons_config`, if present, it is necessary to pass
      additional parameters in the invoice request. When you get `result:
      false`, you need to analyse the error code in the `error_code` field (see
      [description of error codes](/errors-list)). If the `error code` is not
      fatal, then you need to wait for the [server notification](/callbacks). If
      the `error code` is fatal, then communication with our API is over.


      4. After verifying
      [invoice/try](/api-reference/invoice-create/invoice-preliminary-calculation),
      the shop sends an invoice request
      [invoice/create](/api-reference/invoice-create/invoice-issue), specifying
      the required parameters and additional information from `add_ons_config`
      (if it is required for the specified payment direction);


      5. The response returns information with the invoice and data to be sent
      by the specified method to the specified URL for making or charging the
      payment. It is necessary to send the user to make a payment. In case
      `result: false`, you need to analyse the error code in the `error_code`
      field (see [description of error codes](/errors-list)). If the `error
      code` is not fatal, then you need to wait for the [server
      notification](/callbacks). If the `error code` is fatal, then
      communication with our API is over, it is necessary to inform the user
      that the payment was not created.


      6. After the payment is made or charged by the user, the M4 system [sends
      a notification](/callbacks) to the URL of interaction with the shop,
      containing payment information, for more information, see
      [here](/api-reference/invoice-create/invoice-issue);


      7. After receiving the charge, the payment is considered successfully
      completed.


      ### Two-step payment


      *Most often, a two-stage payment is used for payments by bank cards.*


      ![Invoice Two Stage Flow
      Diagram](assets/common/images/en/invoice-two-stage-flow.v1.png)


      1. User generates an order on the shop's website;


      2. Shop sends a request for a preliminary calculation of the issued
      invoice and receiving additional parameters
      [invoice/try](/api-reference/invoice-create/invoice-preliminary-calculation);


      3. When receiving `result: true`, the availability of additional
      information in `add_ons_config` is checked, if present, additional
      parameters should be passed in the invoice request. When you get `result:
      false`, you need to analyse the error code in the `error_code` field (see
      [description of error codes](/errors-list)). If the `error code` is not
      fatal, then you need to wait for the [server notification](/callbacks). If
      the `error code` is fatal, then communication with our API is over.


      4. After verification
      [invoice/try](/api-reference/invoice-create/invoice-preliminary-calculation)
      shop sends invoice request
      [invoice/hold](/api-reference/invoice-create/funds-hold-two-stage-payments),
      specifying the required parameters and additional information from
      `add_ons_config` (if it is required for the specified payment way);


      5. The response returns information with the invoice issued and data to be
      sent by the specified method to the specified URL for making or charging
      the payment. It is necessary to refer the user to make the payment. In
      case `result: false`, you need to analyse the error code in the
      `error_code` field (see [description of error codes](/errors-list)). If
      the `error code` is not fatal, then you need to wait for the [server
      notification](/callbacks). If the `error code` is fatal, then
      communication with our API is over, it is necessary to inform the user
      that the payment was not created.


      6. After payment is completed by the user, the M4 system [sends a
      notification](/callbacks) to the shop's interaction URL, with information
      about the blocking of funds;


      7. After the funds are blocked on the client's account, you can charge the
      payment
      [invoice/charge](/api-reference/invoice-create/confirmation-of-funds-withdrawal-charge)
      or cancel the holding
      [invoice/unhold](/api-reference/invoice-create/cancellation-of-funds-holding);


      8. The response returns information with the result of charge (sometimes
      the payment status may not be final, then you should wait for the
      notification);


      9. M4 system [will send a notification](/callbacks) to the URL of the
      interaction of the shop with the final status regarding the confirmation
      of funds withdrawal.


      ### Ensuring payments idempotency


      <div class="warning">

      The system has duplication protection for invoice creation,
      <code>shop_order_id</code> should be unique within a single shop.

      </div>
  - name: invoice-refund
    x-displayName: Refunds
    description: >
      The refund of the paid invoice can be full or partial.


      * In case of a full refund, you refund the successfully paid payment in
      full.

      * In case of a partial refund - a part of the payment amount, for example,
      if you want to refund a part of the purchase.


      After confirmation of the refund by the payment system, the M4 system
      [will send a notification](/callbacks) with details

      of refund to the URL transferred in the request when creating the refund.
      A detailed description of the notification format

      is described [here](/callbacks#refund-notification-example).


      Please note that if you receive `result: false` in response in case of a
      synchronous response to a request, this means that

      you need to analyse the error code in the `error_code` field (see
      [description of error codes](/errors-list)). If the `error code` is not
      fatal, then you need to wait for the [server notification](/callbacks). If
      the `error code` is fatal, then the refund transaction will not be created
      (it will either not be created at all if basic checks

      have not passed, or it will be created with the immediate status
      `FAILED`). In this case, communication with our API is over.


      If in case of a synchronous response to a request in the response you
      received `result: true`, this means that you need to check the status

      of the refund transaction in the response body:

      it can be final (`SUCCESS`, `FAILED`), and then communication with the API
      is over, or it can be `WAITING` — then

      you have to wait for some time for a [server notification](/callbacks)
      from us with the final status.


      <div class="success">

      Refunds are made in the currency of the paid invoice, under which the
      refund transaction is carried out.

      </div>


      <div class="warning">

      Check with the manager for available refund ways for specific payment
      methods.

      </div>
  - name: callbacks
    x-displayName: Interaction format
    description: >
      ### Issued invoice notice after payment or refund


      After changing the payment status or returning to one of the final ones,
      the M4 system sends a notification to the shop to the URL specified in the
      shop settings or in the request body (if specified in the description of
      the request parameters).


      <div class="warning">

      <p>To successfully receive server-side notifications, please make sure
      that your server receiving HTTP requests from us is configured according
      to the current security standards described on <a
      href="https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html">https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html</a></p>

      <p>Pay special attention to the TLS ciphers you support.</p>

      </div>


      Notifications for payments and refunds are delivered to one callback URL.
      You can distinguish notifications by the value of the GET parameter named
      `type` in the URL from which you received the notification.

      Possible values of `type`:

      * `invoice` - payment notification

      * `refund` - refund notification


      Server notifications are sent from the following IP addresses:


      |IP addresses|

      |-|

      |35.198.100.222|

      |35.198.175.25|


      HTTP protocol is used to send the notification:


      * Method: `POST`

      * Format: `Content-Type: application/json`


      <div class="success">

      <p>If necessary, the support service can enable an alternative
      notification format: <code>Content-Type:
      application/x-www-form-urlencoded</code>, in this case, all the
      transmitted parameters will have a string representation.</p>

      </div>


      <div class="attention">

      <p>It is <strong>necessary</strong> to check the values from the
      notification with the values in the invoice, and <strong>to check</strong>
      signature in the notification.</p>

      <p>The signature is generated using the same algorithm as when issuing the
      invoice.</p>

      <p>All the not-null and non-empty parameters present in the notification
      are involved in the signature validation, including zero values. At the
      same time, <code>null</code> values and empty strings are not involved in
      signature validation and are excluded.</p>

      </div>


      <p>Consider building your system using forward compatibility strategy to
      be ready to handle new parameters in the server notifications without need
      to upgrade your own system.</p>


      ### Expected response


      If the notice is received and processed correctly, it is necessary to
      return the status `200` and the message body `OK` (`text/plain`) to the
      `HTTP` response. Otherwise, notices will be sent again, with an increasing
      interval, including only 25 attempts, the last one at the end of the day.


      ## Payment notification example


      <SchemaDefinition schemaRef="#/components/schemas/InvoiceCallBack" />


      ## Refund notification example


      <SchemaDefinition schemaRef="#/components/schemas/RefundCallBack" />


      ## Example of Python code to verify the signature of a request


      The algorithm implemented below on the example of a server payment
      notification is the same for a server refund notification.


      ```python

      # Resulting notification string (in format application/json)

      request_body_json = """
          {
            "shop_id": 1,
            "shop_order_id": "The store's order ID",
            "description": "Your payment description",
            "shop_amount": 100.0,
            "shop_refund": 19.0,
            "shop_currency": 840,
            "payment_id": 1234,
            "client_price": 100.0,
            "ps_currency": "840",
            "payway": "payway_example",
            "ps_data": "{\\"amount\\": \\"20.00\\", \\"bill_id\\": \\"i_100\\", \\"ccy\\": \\"USD\\", \\"command\\": \\"bill\\", \\"comment\\": \\"[i_100] Payment\\", \\"error\\": 0, \\"prv_name\\": \\"PaymentSystem\\", \\"ps_payer_account\\": \\"150010000097\\", \\"status\\": \\"paid\\", \\"user\\": \\"tel:+150010000097\\"}",
            "created": "2026-08-27T15:38:07",
            "updated": "2026-08-27T15:38:07",
            "status": "success",
            "addons": "{\\"callback_rejected_url\\": \\"https://some-shop.com/callback-rejected-url\\", \\"callback_url\\": \\"https://some-shop.com/callback-url\\", \\"description\\": \\"Some payment\\", \\"failed_url\\": \\"https://some-shop.com/fail\\", \\"phone\\": \\"150010000097\\", \\"success_url\\": \\"https://some-shop.com/success\\"}",
            "sign": "26bcafa4b08dcfa901e47caa977c75ed286bb4390fb8271eb96e2f46470ffbf7"
      }"""


      import json

      parsed_request = json.loads(request_body_json)


      # Resulting notification string (in format
      application/x-www-form-urlencoded)

      if content_type == 'application/x-www-form-urlencoded':
          request_body_form_urlencoded = (
              'shop_id=1&shop_order_id=The+store's+order+ID&description=Your+payment+description&s'
              'hop_amount=20.0&shop_refund=19.0&shop_currency=840&payment_id=100&'
              'client_price=20.0&ps_currency=840&payway=payway_example&ps_data='
              '%7B%22amount%22%3A+%2220.00%22%2C+%22bill_id%22%3A+%22i_100%22%2C+'
              '%22ccy%22%3A+%22USD%22%2C+%22command%22%3A+%22bill%22%2C+%22commen'
              't%22%3A+%22%5Bi_100%5D+Payment%22%2C+%22error%22%3A+0%2C+%22prv_na'
              'me%22%3A+%22PaymentSystem%22%2C+%22ps_payer_account%22%3A+%2297151'
              '0000000%22%2C+%22status%22%3A+%22paid%22%2C+%22user%22%3A+%22tel%3'
              'A%2B150010000097%22%7D&created=2026-08-27T15%3A38%3A07&updated=202'
              '0-08-21T15%3A38%3A07&status=success&addons=%7B%22callback_rejected'
              '_url%22%3A+%22https%3A%2F%2Fsome-shop.com%2Fcallback-rejected-url%'
              '22%2C+%22callback_url%22%3A+%22https%3A%2F%2Fsome-shop.com%2Fcallb'
              'ack-url%22%2C+%22description%22%3A+%22Some+payment%22%2C+%22failed'
              '_url%22%3A+%22https%3A%2F%2Fsome-shop.com%2Ffail%22%2C+%22phone%22'
              '%3A+%22150010000097%22%2C+%22success_url%22%3A+%22https%3A%2F%2Fso'
              'me-shop.com%2Fsuccess%22%7D&sign=26bcafa4b08dcfa901e47caa977c75ed2'
              '86bb4390fb8271eb96e2f46470ffbf7'
          )
          from urllib.parse import parse_qsl
          parsed_request = dict(parse_qsl(request_body_form_urlencoded))

      print(parsed_request)

      # {

      #     'shop_id': 100,

      #     'shop_order_id': 'The store's order ID',

      #     'description': 'Some payment',

      #     'shop_amount': 20.0,

      #     'shop_refund': 19.0,

      #     'shop_currency': 840,

      #     'payment_id': '100',

      #     'client_price': 20.0,

      #     'ps_currency': 840,

      #     'payway': 'payway_example',

      #     'ps_data': '{"amount": "20.00", "bill_id": "i_100", "ccy": "USD",
      "command": "bill", "comment": "[i_100] Payment", "error": 0, "prv_name":
      "PaymentSystem", "ps_payer_account": "150010000097", "status": "paid",
      "user": "tel:+150010000097"}',

      #     'created': '2026-08-27T15:38:07',

      #     'updated': '2026-08-27T15:38:07',

      #     'status': 'success',

      #     'addons': '{"callback_rejected_url":
      "https://example.com/callback-rejected-url", "callback_url":
      "https://example.com/callback-url", "description": "Your payment
      description", "failed_url": "https://example.com/fail", "phone":
      "150010000097", "success_url": "https://example.com/success"}',

      #     'sign':
      '5d3ea83ec487fb1a769942b348741eafa5b124073d9bca968977731b724ee397',

      # }


      # Let's get a list of sorted keys for signature generation

      keys = sorted(parsed_request)


      # Let's remove the signed key from them.

      keys.remove('sign')


      print(keys)

      # This is how the resulting list will look like

      #     ['addons',

      #      'client_price',

      #      'created',

      #      'description',

      #      'payment_id',

      #      'payway',

      #      'ps_currency',

      #      'ps_data',

      #      'shop_amount',

      #      'shop_currency',

      #      'shop_id',

      #      'shop_order_id',

      #      'shop_refund',

      #      'status',

      #      'updated']


      # Let's compose a line using the sorted key values obtained in the
      previous step

      values_to_sign = []

      for k in keys:
          if parsed_request[k] != '' and parsed_request[k] is not None:
              values_to_sign.append(str(parsed_request[k]))

      # Let's form the final signature and check its value with the value
      received in the response

      string_to_sign = ':'.join(values_to_sign) + '<secret_key_here>'

      import hashlib

      sign = hashlib.sha256(string_to_sign.encode()).hexdigest()

      assert sign == parsed_request['sign']

      ```
  - name: invoice-recurrent
    x-displayName: Recurrent invoice
    description: >
      <div class="attention">This feature is available only after approval by
      the manager.</div>


      You can withdraw funds regularly from the payment instrument of the buyer
      without repeated entry of details and without participation of the payer
      to initiate the next payment. With such way of funds withdrawal the user
      should only confirm the first payment or linking of the payment
      instrument, all subsequent payments will be made without his/her
      participation.


      To create the first payment in the chain and to generate the payment
      token, pass `issue_payment_token: true` in
      [invoice/create](/api-reference/invoice-create/invoice-issue) or
      [invoice/hold](/api-reference/invoice-create/funds-hold-two-stage-payments).


      You will then receive a [notification](/callbacks) with `payment_token`
      inside `ps_data`. Save that token for subsequent charges.


      <div class="warning">Parameter <strong>payment_token</strong> is sent only
      after a successful transaction.</div>


      For each following payment, submit `payment_token: "<payment token>"` in
      [invoice/create](/api-reference/invoice-create/invoice-issue). The
      response may return `method: null` and `url: null` when no redirect to the
      payment page is required; the final result arrives via
      [notification](/callbacks).
  - name: invoice-statuses
    x-displayName: Invoice statuses
    description: >
      List of possible statuses of the created invoice.


      | Numerical identifier |
      Description                                          | Final     |

      |:-----:|---------------------------------------------------------------------|:---------:|

      |  1    | Payment request has been
      created                                    | &minus;   |

      |  2    | Payment is awaiting user
      action                                     | &minus;   |

      |  3    | Payment system has failed to create the
      payment                     | &minus;   |

      |  4    | Payment has been
      successful                                         | &plus;    |

      |  5    | Payment system has failed to receive a payment
      notice               | &minus;   |

      |  6    | M4 payment system has rejected the operation               |
      &plus;    |

      |  8    | Funds for the invoice are withheld (held) by the payment
      system     | &minus;   |
  - name: withdraw-create
    x-displayName: Payout creation
    description: >
      ### Process of shop payouts generation is as follows:


      ![Withdraw Flow Diagram](assets/common/images/en/withdraw-flow.v1.png)


      1. Shop executes a request for a preliminary calculation and receiving
      additional parameters for further creation of the payout using the method
      [withdraw/try](/api-reference/withdraw-create/payout-preliminary-calculation);


      2. If `result: true`, the shop sends request for a preliminary check of
      the existence and possibility of adding funds to the account
      [check_account](/api-reference/withdraw-create/checking-the-account-for-the-possibility-of-replenishment),
      to the specified payment way (if necessary, specify additional parameters
      obtained from the previous request from the `account_info_config` field);


      3. If `result: true`, verify availability of additional information in the
      `account_info` field, if available, it is necessary to pass additional
      parameters in the payout creation request. When getting `result: false`,
      analyse the error code in the `error_code` field (see [description of
      error codes](/errors-list)). If the `error code` is not fatal, then you
      need to start requesting the status of the transaction after a certain
      time (for 2 hours at 30-second intervals). If the `error code` is fatal
      the communication with our API is over.


      4. Shop submits a request for payout creation
      [withdraw/create](/api-reference/withdraw-create/payout-creation),
      specifying the required parameters and additional information from
      `account_info` (if it is required for the specified payment way);


      5. The response returns information with the generated payout request and
      indicating the amounts and the payout ID. In this case, the part of the
      balance of the shop from which the payout is made is frozen until the
      final payout status.


      6. After payout creation, it is necessary to make a request to get the
      status of the created payout
      [withdraw/status](/api-reference/withdraw-create/payout-status-request-by-id-of-the-payout-created-in-m4-system)
      or
      [withdraw/shop_payment_status](/api-reference/withdraw-create/payout-status-request-by-the-shop-payout-number),
      before receiving the final status.


      <div class="attention">

      Status requests are recommended to be made at 30-second intervals.

      </div>


      7. After final status is received, the payout is considered completed, and
      the funds are debited from the shop's balance (or returned to the balance
      if the payout was not completed).


      ### Guidelines for creation and verification of payout requests


      If you received `result: true` after creating the payout, you should
      immediately check the `data.status` field, perhaps there will already be a
      final [status](/withdraw-statuses), for example `6 (Rejected)` and in this
      case, you do not need to make a request for the payout status.


      If you receive the `Read timeout` error at the payout creation request,
      then you need to make a status request by the shop's payout number
      [withdraw/shop_payment_status](/api-reference/withdraw-create/payout-status-request-by-the-shop-payout-number)
      and if the response returns an error stating the absence of such a payout,
      you can repeat the request to create a payout. If the payout status is
      returned in the response, then it means that it was created and you need
      to focus on this status.


      Reason for payout rejection ([getting status 6](/withdraw-statuses)) can
      be clarified through the support service <a
      href="mailto:support@m4psp.com">support@m4psp.com</a>.


      ### Securing payouts idempotency


      <div class="warning">

      System has duplication protection for payouts,
      <code>shop_payment_id</code> must be unique within a single shop.

      </div>
  - name: withdraw-statuses
    x-displayName: Payout statuses
    description: >
      If the payout has been successfully created, the response will contain a
      unique payment identifier and its status.


      The status can be final and non-final, for non-final status, you must make
      a status request before receiving the final status.


      | Numerical identifier | Description                        | Final   |

      |:-----:|---------------------------------------------------|:--------:|

      |  1    | Payout has been created, awaits processing        | &minus; |

      |  3    | Sent to the payment system                        | &minus; |

      |  4    | Payout error on the part of the payment system    | &minus; |

      |  5    | Successfully completed                            | &plus;  |

      |  6    | Rejected by the payment system                    | &plus;  |

      |  9    | Network error on the part of the payment system   | &minus; |
  - name: other-shop-methods
    x-displayName: Other shop methods
    description: |
      ### Other methods available for the shop
  - name: errors-list
    x-displayName: List of possible errors
    description: >
      ### List of possible M4 API errors


      You can use this data to control the logic of your application, analyze
      and solve problems, output messages

      to the user, and for any other purpose. For example, if you received
      `error_code: 11` in the response, then most likely you

      incorrectly specified the value of the `shop_id` parameter in the request
      body.


      If you receive `result: false` in the response, this means that an error
      occurred, and the transaction was either not created (

      for example, in case of request body validation error), or ended with an
      error (for example, the payment system returned an error when

      trying to perform a transaction). If the `error code` is not fatal, then
      you need to wait for the [server notification](/callbacks) (applies to
      [invoice](/invoice-create) or [refund](/invoice-refund) transactions) or
      after a certain time start requesting the status of the transaction
      (applies to [payout](/withdraw-create) transactions) (for 2 hours at
      30-second intervals). If the `error code` is fatal the communication with
      our API is over.


      If you receive `result: true` in response, it means that the transaction
      was created successfully. If the transaction status in the synchronous

      response is not final (or is absent for some types of transactions), then
      you need

      to wait for the [server notification](/callbacks) or after a certain time
      start requesting the status

      of the transaction (applies only to [payout](/withdraw-create)
      transactions). After receiving the final status of the transaction,

      the communication with our API is over.


      | Error code |
      Description                                                                                                                                                                        
      |  Fatal  |

      |------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------:|

      | 1          | Payway has not been
      found                                                                                                                                                          
      | &plus;  |

      | 2          | Payway is not
      active                                                                                                                                                               
      | &plus;  |

      | 3          | Payway is not
      available                                                                                                                                                            
      | &plus;  |

      | 4          | The specified amount is too small (payway
      restriction)                                                                                                                             
      | &plus;  |

      | 5          | The specified amount is too big (payway
      restriction)                                                                                                                               
      | &plus;  |

      | 6          | A non-unique operation identifier has been transferred on
      the part of the
      shop                                                                                                     
      | &plus;  |

      | 7          | Operation has not been
      found                                                                                                                                                       
      | &plus;  |

      | 8          | Operation is being
      processed                                                                                                                                                       
      | &plus;  |

      | 9          | Insufficient
      balance                                                                                                                                                               
      | &plus;  |

      | 10         | Invalid request
      parameters                                                                                                                                                         
      | &plus;  |

      | 11         | Shop has not been
      found                                                                                                                                                            
      | &plus;  |

      | 12         | Shop is not
      active                                                                                                                                                                 
      | &plus;  |

      | 13         | Account has not been found in M4
      system                                                                                                                                    
      | &plus;  |

      | 14         | Account status does not allow
      operations                                                                                                                                           
      | &plus;  |

      | 15         | Request from the current IP has been
      rejected                                                                                                                                      
      | &plus;  |

      | 16         | Currency exchange rate has not been
      found                                                                                                                                          
      | &plus;  |

      | 17         | Invalid contract type for the
      shop                                                                                                                                                 
      | &plus;  |

      | 18         | Invalid account
      type                                                                                                                                                               
      | &plus;  |

      | 19         | Unable to perform operation for shop with the status of an
      aggregator                                                                                                              
      | &plus;  |

      | 20         | Invalid project
      ID                                                                                                                                                                 
      | &plus;  |

      | 21         | Project is
      inactive                                                                                                                                                                
      | &plus;  |

      | 22         | Invalid shop
      currency                                                                                                                                                              
      | &plus;  |

      | 23         | Account deposit limit
      exceeds                                                                                                                                                      
      | &plus;  |

      | 24         | Invalid payee
      balance                                                                                                                                                              
      | &plus;  |

      | 25         | Zero amount is
      specified                                                                                                                                                           
      | &plus;  |

      | 26         | Amount is less than
      zero                                                                                                                                                           
      | &plus;  |

      | 27         | Daily limit has been
      exceeded                                                                                                                                                      
      | &plus;  |

      | 40         | Operation with specified BIN is
      restricted                                                                                                                                         
      | &plus;  |

      | 41         | Transaction to this payment instrument is
      forbidden                                                                                                                                
      | &plus;  |

      | 100        | Operation has an invalid
      status                                                                                                                                                    
      | &plus;  |

      | 101        | Unable to refund since the invoice has a status other than
      Success
      (4)                                                                                                             
      | &plus;  |

      | 102        | Refund amount exceeds the available refund
      amount                                                                                                                                  
      | &plus;  |

      | 103        | Transaction for this payment method is not
      supported                                                                                                                               
      | &plus;  |

      | 104        | Cannot execute a refund because an incomplete refund
      already exists. Wait for the current refund to complete before creating a
      new one.                                             | &plus;  |

      | 1001       | Payment system is unable to process the request now. Please
      try again
      later.                                                                                                       
      | &minus; |

      | 1002       | Payment system has returned the "Access error" status.
      Please contact the payment system for further
      information.                                                                  
      | &plus;  |

      | 1003       | Invalid request parameters. Please verify the accuracy of
      the payment details and retry the request
      later.                                                                         
      | &plus;  |

      | 1004       | The payment amount is less or greater than the allowed
      limit. Please ensure that the payment amount complies with the
      requirements of the payment system or bank.                   | &plus;  |

      | 1005       | The transaction limit has been exceeded. Please contact
      bank or the payment system to get information about the reasons for
      reaching the transaction limit.                         | &plus;  |

      | 1006       | The account was not found in the payment system. Please
      check the correctness of the entered data and retry the
      request.                                                            |
      &plus;  |

      | 1007       | An error occurred in the payment system. Request the status
      of the transaction or wait for a server
      notification.                                                                  
      | &minus; |

      | 1008       | Insufficient funds in the account to process the payment.
      Please ensure that there are sufficient funds in the account and retry the
      request.                                       | &plus;  |

      | 1009       | Insufficient identification status of the
      wallet                                                                                                                                   
      | &plus;  |

      | 1010       | The account is blocked. Request information about the
      reasons for the blockage and the actions required to unblock the account
      in the payment system or use an alternative account. | &plus;  |

      | 1011       | Operation is forbidden by a payment system. Please contact
      the payment system for further
      information.                                                                             
      | &plus;  |

      | 1012       | Operation is rejected by payment system. Please contact the
      payment system for further
      information.                                                                                
      | &plus;  |

      | 1013       | Account is locked in payment
      system                                                                                                                                                
      | &minus; |

      | 1014       | Incorrect data in request
      parameters                                                                                                                                               
      | &minus; |

      | 1015       | Transaction lifetime was
      expired                                                                                                                                                   
      | &plus;  |

      | 1016       | The operation has been declined by the payment system. The
      user has an unpaid transaction that needs to be either declined or
      completed.                                            | &plus;  |

      | 1017       | The specified currency for the operation is unavailable.
      Please contact the payment system for information on the available
      currencies.                                             | &plus;  |

      | 1018       | No suitable options were found for the transaction. Please
      try again
      later.                                                                                                        
      | &plus;  |

      | 1019       | The user did not confirm or cancel the operation. Please
      try again
      later.                                                                                                          
      | &plus;  |

      | 1020       | The transaction failed KYT
      verification.                                                                                                                                           
      | &plus;  |

      | 1100       | Invalid CVV/CVC code. Please verify the accuracy of the
      entered CVV/CVC code on the back of the credit
      card.                                                                       
      | &plus;  |

      | 1101       | Suspicion of fraudulent activity. Please contact the
      payment system or bank for further
      information.                                                                               
      | &plus;  |

      | 1102       | The operation has been rejected by the payment system.
      Please verify the accuracy of the payment details and retry the request
      later.                                               | &plus;  |

      | 1103       | The operation has been rejected by the bank. Please contact
      the bank to determine the reason for the
      rejection.                                                                    
      | &plus;  |

      | 1104       | The operation with this payment instrument is prohibited.
      Please contact bank or the payment system for information on the reasons
      for the prohibition.                             | &plus;  |

      | 1105       | The card has expired. Please check the expiration date of
      the card provided during the payment. If the card has indeed expired,
      please use a card with a valid expiration date.     | &plus;  |

      | 1106       | Invalid card number. Please check the correctness of the
      entered number and retry the
      request.                                                                                     
      | &plus;  |

      | 1107       | 3D-Secure authentication is required. Please contact the
      payment system or bank for additional
      information.                                                                        
      | &plus;  |

      | 1108       | The payment token has expired. Obtain a new token and retry
      the
      request.                                                                                                           
      | &plus;  |

      | 1109       | Transaction rejected by MPI. Please repeat the payment
      using another bank
      card.                                                                                                    
      | &plus;  |

      | 2000       | Another
      error                                                                                                                                                                      
      | &plus;  |
paths:
  /invoice/create:
    post:
      tags:
        - invoice-create
      summary: Invoice issue
      description: >
        Additional parameters can be transferred in the request, for example:


        * `description` – invoice description,

        * `phone` – phone number linked to the wallet;

        * `account` – card number;


        The list of these parameters depends on the payway (`payway`). The
        required additional parameters for the payway can be found in the
        request "Getting payment methods for input"
        [shop_input_config/shop](/api-reference/invoice-create/getting-payment-methods-for-input)
        in the `add_ons_config` response field.


        ### Redirecting to invoice payment forms


        If the request is successful, API will return the parameters necessary
        to redirect the user to the payment system for payment. These parameters
        will be in the `data` field of the response. The `data.data` field
        contains the parameters to be transferred during redirection (in the
        form of `GET` or `POST` request parameters).


        The redirection method depends on the `method` parameter. The generated
        request must be sent to the URL specified in the `url` field of the
        `data` field.


        For example, if you receive a `POST` in the `method` parameter to
        redirect a client to pay an invoice, you need to generate an HTML form
        from the parameters received in the response body (these parameters will
        differ for different payment systems).


        An example of forming an HTML form using the `jinja2` template language:


        ```jinja2

        <form method="POST" action="{{ data['url'] }}">
            {% for param, value in data['data'].items() %}
              <input name="{{ param }}" value="{{ value }}" />
            {% endfor %}
        </form>

        ```


        For the data specified in the example response below, the following HTML
        form will be obtained:


        ```html

        <form method="POST" action="https://test-checkout.domain.com/form/">
          <input name="transaction_id" value="a1b2c3" />
          <input name="payment_type" value="card" />
          <input name="fail_url" value="https://metaexamplesite.com/payment/?status=fail" />
          <input name="success_url" value="https://metaexamplesite.com/payment/?status=success" />
          <input type="submit" />
        </form>

        ```


        In case of `"method": "GET"` it is required to perform HTTP redirect to
        the URL with the parameters (using
        [percent‐encoding](https://en.wikipedia.org/wiki/Percent-encoding)),
        received in the `data.data` response field.


        The URL is generated according to the following algorithm:


        ```python

        import urllib.parse

        redirect_url = '{url}?{parameters}'.format(url=data['url'],
        parameters=urllib.parse.urlencode(data['data']))

        ```


        An example of the formed URL:
        `https://test-checkout.domain.com/form/?transaction_id=a1b2c3&payment_type=card&fail_url=https%3A%2F%2Fmetaexamplesite.com%2Fpayment%2F%3Fstatus%3Dfail&success_url=https%3A%2F%2Fmetaexamplesite.com%2Fpayment%2F%3Fstatus%3Dsuccess`


        <div class="attention">

        Please note that the parameters <code>failed_url</code>,
        <code>success_url</code>, <code>callback_url</code>,
        <code>callback_rejected_url</code> specified in the shop settings have
        priority over those specified in request. If you want to use unique url
        for each request, you need to inform the manager about it.

        </div>


        ### Payer Browser Authentication for 3D Secure


        For 3ds 2.0 payments with card data to be successful, the payer's
        browser information must be collected.


        You can collect the data yourself or let our service perform this for
        you. If you collect the data on your end, please ensure that all the
        necessary values are included to the payment initiation request
        [/invoice/create](/api-reference/invoice-create/invoice-issue).


        As an example, the provided JavaScript code could be employed to obtain
        the Payer Browser information. Please be aware that the `client_info`
        fields provided below do not include `browser_accept_header`.


        ```js

        let client_info = {
            "browser_java_enabled": window.navigator.javaEnabled(),
            "browser_javascript_enabled": true,
            "browser_language": window.navigator.language,
            "browser_color_depth": window.screen.colorDepth.toString(),
            "browser_screen_height": window.screen.height.toString(),
            "browser_screen_width": window.screen.width.toString(),
            "browser_tz": (new Date()).getTimezoneOffset().toString(),
            "browser_user_agent": window.navigator.userAgent,
            "challenge_window_size": "05"
        }

        ```


        If the payer's browser data is not provided in the
        [/invoice/create](/api-reference/invoice-create/invoice-issue) request,
        it will be necessary to redirect the payer to our service as an
        intermediate step using a `data` object, so that our service can collect
        the necessary browser data. See [Redirecting to invoice payment
        forms](#redirecting-to-invoice-payment-forms) for the details on
        redirect.


        <div class="success">

        <p>Fields involved in request signature generation:</p>


        * `amount`

        * `currency`

        * `payway`

        * `shop_id`

        * `shop_order_id`

        </div>
      operationId: post-invoice-create
      parameters:
        - name: sign
          in: header
          required: true
          schema:
            type: string
            example: sign-your-request
          description: Request signature
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InvoiceCreatePayload.v1'
        description: ''
      responses:
        '200':
          description: ''
          x-summary: OK
          content:
            application/json:
              schema:
                oneOf:
                  - title: Invoice has been successfully issued
                    allOf:
                      - $ref: '#/components/schemas/ResponseOK.v1'
                      - properties:
                          data:
                            $ref: '#/components/schemas/InvoiceCreateInfo.v1'
                  - $ref: '#/components/schemas/ResponseFail.v1'
      security:
        - Request signature: []
components:
  schemas:
    InvoiceCreatePayload.v1:
      oneOf:
        - $ref: '#/components/schemas/InvoiceCreateCard.v1'
    ResponseOK.v1:
      title: Successful response
      type: object
      allOf:
        - $ref: '#/components/schemas/Response.v1'
        - properties:
            result:
              example: true
            message:
              example: Ok
            error_code:
              example: 0
    InvoiceCreateInfo.v1:
      title: Invoice payment form
      type: object
      description: ''
      properties:
        data:
          example:
            MD: 4a9f8b2c6d1e0f7a3b5c8d2e9f0a1b3c
            PaReq: >-
              7xR2wM9qL1vK5bN4pZ8cC3fG6hJ0oO1iI3sD5aA7eE9tT2yY4uU6rR8wW0qQ2mM4nN6bB8vV0cC2xX4zZ6lL8kK0jJ2hH4gG6fF8dD0sS2aA4pP6oO8iI0uU2yY4tT6rR8eE0wW2qQ4mM6nN8bB0vV2cC4xX6zZ8lL0kK2jJ4hH6gG8fF0dD2sS4aA6pP8oO0iI2uU4yY6tT8rR0eE2wW4qQ6mM8nN0bB2vV4cC6xX8zZ0lL2kK4jJ6hH8gG0fF2dD4sS6aA8pP0oO2iI4uU6yY8tT0rR2eE4wW6qQ8mM0nN2bB4vV6cC8xX0zZ2lL4kK6jJ8hH0gG2fF4dD6sS8aA0pP2oO4iI6uU8yY0tT2rR4eE6wW8qQ0mM2nN4bB6vV8cC0xX2zZ4lL6kK8jJ0hH2gG4fF6dD8sS0aA2pP4oO6iI8uU0yY2tT4rR6eE8wW0qQ2mM4nN6bB8vV0cC2xX
            TermUrl: >-
              https://test-api.domain.com/v1/invoice/finish3ds/4a9f8b2c6d1e0f7a3b5c8d2e9f0a1b3c
          type: object
          nullable: true
          description: >
            Data to be sent using the `method` method to `url`. The fields below
            are indicated for example,

            the real names of the fields and their number will differ depending
            on the payment system.
          properties:
            key1:
              type: string
            key2:
              type: string
        id:
          type: number
          example: 340198
          description: Unique invoice identifier in M4 system
        method:
          type: string
          nullable: true
          description: >-
            Method of sending `data` to `url`. If you received `null`, then you
            do not need to redirect to the payment form.
          enum:
            - GET
            - POST
          example: POST
        url:
          type: string
          format: uri
          nullable: true
          example: https://test-checkout.domain.com/form/
          description: >-
            URL subject to which the contents of the `data` field should be sent
            by the `method`. If `null` is received, then you do not need to send
            it.
      required:
        - data
        - id
        - method
        - url
    ResponseFail.v1:
      title: Error response
      type: object
      description: |
        # Error response 😎
      allOf:
        - $ref: '#/components/schemas/Response.v1'
        - properties:
            data:
              type: object
              example: null
              nullable: true
            result:
              example: false
            message:
              example: Shop (id = 1520) is not found
            error_code:
              example: 12
    InvoiceCreateCard.v1:
      title: Bank card payment
      allOf:
        - $ref: '#/components/schemas/InvoiceCreateBase.v1'
        - $ref: '#/components/schemas/InvoiceCreateClientIP.v1'
        - $ref: '#/components/schemas/InvoiceCreateExpiresAt.v1'
        - type: object
          properties:
            card:
              type: object
              description: >-
                Bank card details should be sent when:

                - You have a PCI DSS certificate

                - You do not need a page on the M4 side to get card details from
                the buyer


                In case the payment way to the cards is used and the card data
                is not transmitted, the response to the request will contain a
                link to redirect the buyer to enter the card details.

                Also, `method`, `url` and `data` will be filled in if the user
                needs to be redirected to pass the 3DSecure check.
              properties:
                number:
                  type: string
                  description: Bank Card number
                  example: '5395455214142417'
                cardholder:
                  type: string
                  pattern: ' ^[0-9A-Z-/ _.'']{1,26}$'
                  description: >-
                    Cardholder name. If name is not provided default value «Card
                    Holder» will be used
                  example: ADAM SMITH
                expiry_month:
                  type: string
                  pattern: ' (^0?[1-9]{1}$)|(^1[012]{1}$)'
                  description: Bank card expiration month
                  example: '08'
                expiry_year:
                  type: string
                  description: Bank card expiration year
                  pattern: ^\d{2}$
                  example: '30'
                cvv:
                  type: string
                  description: Secure code
                  example: '184'
                  minLength: 3
                  maxLength: 4
              required:
                - number
                - expiry_month
                - expiry_year
                - cvv
            issue_payment_token:
              type: boolean
              example: false
              description: >-
                This parameter is used to generate a payment token. More details
                [invoice/recurrent](/invoice-recurrent)
            client_info:
              type: object
              description: >
                Payer browser information.


                See [Payer Browser Authentication for 3D
                Secure](#payer-browser-authentication-for-3d-secure) for the
                details of the data gathering.
              properties:
                browser_accept_header:
                  type: string
                  description: >
                    Exact HTTP Accept header content as sent by the Payer's
                    browser to Merchant's site.\

                    Example: `"text/html"`
                  example: >-
                    text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8
                browser_java_enabled:
                  type: boolean
                  description: >
                    The ability to execute Java in a browser.\

                    It is recommended to obtain browser values from the global
                    object `navigator`: `navigator.javaEnabled`.
                  example: false
                browser_javascript_enabled:
                  type: boolean
                  description: >
                    The ability to execute JavaScript in a browser.\

                    If the value is not provided, the default value is `true` is
                    set.
                  example: true
                browser_language:
                  type: string
                  description: >
                    Browser language according to the [IETF
                    BCP47](https://en.wikipedia.org/wiki/IETF_language_tag)
                    format.\

                    It is recommended to obtain browser values from the global
                    object `navigator`: `navigator.language`.\

                    Example: `"en"`
                  example: en
                browser_color_depth:
                  type: string
                  description: >
                    The value of the device color depth.\

                    It is recommended to obtain browser values from the global
                    object `screen`: `screen.colorDepth`.\

                    Example: `"24"`
                  example: '24'
                browser_screen_height:
                  type: string
                  description: >
                    Screen height in pixels.\

                    It is recommended to obtain browser values from the global
                    object `screen`: `screen.height`.\

                    Example: `"800"`
                  example: '800'
                browser_screen_width:
                  type: string
                  description: >
                    Screen width in pixels.\

                    It is recommended to obtain browser values from the global
                    object `screen`: `screen.width`.\

                    Example: `"480"`
                  example: '480'
                browser_tz:
                  type: string
                  description: >
                    Browser time zone in minutes from UTC.\

                    Recommendation to obtain browser TZ values: call the
                    `getTimezoneOffset()` method.\

                    Example: `"-120"` for UTC+2, `"240"` for UTC-4
                  example: '-120'
                browser_user_agent:
                  type: string
                  description: >
                    Browser User Agent.\

                    It is recommended to obtain browser values from the global
                    object `navigator`: `navigator.userAgent`.\

                    Example: `"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)
                    AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3
                    Safari/605.1.15"`
                  example: >-
                    Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)
                    AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3
                    Safari/605.1.15
                challenge_window_size:
                  type: string
                  description: >
                    Enum: `"01"`, `"02"`, `"03"`, `"04"`, `"05"`.\

                    The accepted values of the window size for the 3DSecure
                    check:

                    * 250 x 400 = `"01"`

                    * 390 x 400 = `"02"`

                    * 500 x 600 = `"03"`

                    * 600 x 400 = `"04"`

                    * Full screen = `"05"`


                    If the value is not provided, the default value `"05"` is
                    set. 
                  example: '05'
          required:
            - client_ip
    Response.v1:
      title: API response
      type: object
      properties:
        result:
          type: boolean
          description: >-
            Boolean value, in case of successful response it will be `true`, in
            case of error – `false`
        message:
          type: string
          description: A textual description of the error, in case of success - simply `Ok`
        error_code:
          type: number
          description: >-
            If this value is greater than `0`, then the request ended with an
            error. [Description of error codes](/errors-list)
      required:
        - data
        - error_code
        - message
        - result
      description: ''
    InvoiceCreateBase.v1:
      allOf:
        - $ref: '#/components/schemas/InvoicePayload.v1'
        - $ref: '#/components/schemas/InvoiceCreateUrls.v1'
    InvoiceCreateClientIP.v1:
      type: object
      properties:
        client_ip:
          type: string
          format: IPv4
          example: 192.168.1.1
          description: Payer IP address
    InvoiceCreateExpiresAt.v1:
      type: object
      properties:
        expires_at:
          title: <ISO 8601>
          type: string
          format: date-time
          example: '2026-06-01T00:00:00Z'
          description: >
            Invoice expiration date in [ISO
            8601](https://en.wikipedia.org/wiki/ISO_8601) format.

            If invoice is not paid until this date, subsequent invoice payment
            will not be possible.
    InvoicePayload.v1:
      title: Invoice issue parameters
      type: object
      allOf:
        - $ref: '#/components/schemas/ShopID.v1'
        - $ref: '#/components/schemas/ShopOrderID.v1'
        - properties:
            amount:
              allOf:
                - title: Invoice amount
                - $ref: '#/components/schemas/Amount.v1'
            currency:
              $ref: '#/components/schemas/Currency.v1'
            payway:
              $ref: '#/components/schemas/PaywayInvoice.v1'
          required:
            - shop_id
            - amount
            - currency
            - payway
            - shop_order_id
            - sign
        - $ref: '#/components/schemas/Description.v1'
    InvoiceCreateUrls.v1:
      type: object
      properties:
        failed_url:
          type: string
          description: >-
            URL where the payer will be redirected after unsuccessful invoice
            payment.
          format: uri
          example: https://your-domain.com/status/failed/
        success_url:
          type: string
          format: uri
          example: https://your-domain.com/status/success/
          description: >-
            URL where the payer will be redirected after successful invoice
            payment.
        callback_url:
          type: string
          description: URL where the notification about successful payment will be sent.
          format: uri
          example: https://your-domain.com/status/callback/
        callback_rejected_url:
          type: string
          description: URL where the notification about unsuccessful payment will be sent.
          format: uri
          example: https://your-domain.com/status/rejected/
    ShopID.v1:
      type: object
      title: Shop ID
      properties:
        shop_id:
          type: integer
          example: 1520
          description: Unique shop identifier in the M4 system.
      required:
        - shop_id
    ShopOrderID.v1:
      type: object
      title: Identifier sent by the shop
      properties:
        shop_order_id:
          type: string
          example: 5b0efa8a-153b-4421-abac-2aba4d772a86
          description: Order ID in your system. *Must be unique for each new invoice.*
          maxLength: 255
      required:
        - shop_order_id
    Amount.v1:
      title: Amount received or withdrawn.
      type: string
      description: |
        Amount received or withdrawn.
        Example: `"227.34"`
      exclusiveMinimum: true
      minimum: 0
      example: '6320.91'
    Currency.v1:
      type: number
      description: >
        Numeric currency identifier in accordance with [ISO
        4217](https://wikipedia.org/wiki/ISO_4217).

        Example: `840`
      title: Currency identifier
      example: 840
    PaywayInvoice.v1:
      title: Payment way
      example: card_payway_usd
      allOf:
        - $ref: '#/components/schemas/Payway.v1'
        - description: >
            Payment way for payment.

            Invoice currency depends on the specified payment way.


            There are two ways to get a list of all payment directions available
            to the shop:

            * Execute API request "Receiving payment methods for input"
            [shop_input_config/shop](/api-reference/invoice-create/getting-payment-methods-for-input).

            * Request register from the support service.
    Description.v1:
      type: object
      properties:
        description:
          type: string
          description: Optional payment description.
          example: Payment for shop_id=1520
          maxLength: 255
    Payway.v1:
      type: string
      maxLength: 150
      pattern: ^[A-Za-z_,\[\]]+$
  securitySchemes:
    Request signature:
      type: apiKey
      in: requestBody
      name: sign
      description: >+
        Every API request must be signed so that we can identify your account.


        The signature is transferred in the request body through the `sign`
        parameter, for example:


        ```json

        {
            "shop_id": 1520,
            "shop_order_id" : "5b0efa8a-153b-4421-abac-2aba4d772a86",
            "amout": "6320.91",
            "currency": 840,
            "payway": "card_invoice_usd",
            "description": "Payment for shop_id=1520",
            "sign": "77a6f7a30876d480d4e771d08cb83800dd5cb874664c77e515ffc052b20293c6"
        }

        ```

        <div class="warning">

        All further request examples do not include the <code>"sign"</code>
        parameter, nevertheless your real requests <strong>must</strong> include
        it in the request body where required.

        </div>


        Signature line is generated according to the following algorithm: all
        request parameters involved in signature generation are ordered in the
        alphabetical order of keys, the values are concatenated with a colon
        (":") and the account secret key is added at the end (without the:
        `sign`), a sha256 hash is generated from the resulting line and its hex
        representation is passed in the sign request parameter.


        ### Example of signature generation for a method
        [invoice/create](/api-reference/invoice-create/invoice-issue):


        1. Determining the list of parameters. It looks as follows for the
        method in consideration:


        <div class="success">

        <p>Fields involved in request signature generation:</p>


        * `shop_id`

        * `shop_order_id`

        * `amount`

        * `currency`

        * `payway`

        </div>


        2. Let's sort keys in alphabetical sequence:


        `"amount", "currency", "payway", "shop_id", "shop_order_id"`


        3. The line for generating the SHA256 hash will be as follows:


        `"6320.91:840:card_invoice_usd:1520:5b0efa8a-153b-4421-abac-2aba4d772a86account-secret-key"`


        Where `account-secret-key` is the secret identification key for your
        account. You can request a key from the support service.


        4. Let's get a hash expression of the generated line using Python code:


        ```python

        >>> string_to_sign =
        '6320.91:840:card_invoice_usd:1520:5b0efa8a-153b-4421-abac-2aba4d772a86account-secret-key'

        >>> import hashlib

        >>> sign = hashlib.sha256(string_to_sign.encode()).hexdigest()

        >>> print(sign)

        '77a6f7a30876d480d4e771d08cb83800dd5cb874664c77e515ffc052b20293c6'

        ```


        <div class="success">

        You can check whether you have generated the signature correctly using
        the service <a
        href="https://www.xorbin.com/tools/sha256-hash-calculator">https://www.xorbin.com/tools/sha256-hash-calculator</a>.

        </div>


````