payout / developers
Guide

Recurrent payment

On this page
  1. Generate API key and secret

    • You can do this in the backoffice (Sandbox or Production) after you have already created an account.
    • It's required to add a notify URL before the API key is generated. This URL will be used for sending webhook notifications (POST HTTP Requests) about the state of checkouts and other events.
  2. Make an authorization call to get a Bearer token

    Command Line
    curl --location --request POST 'https://sandbox.payout.one/api/v1/authorize' \
    --header 'Content-Type: application/json' \
    --header 'Accept: application/json' \
    --data-raw '{
     "client_id": "DC995618-7ED8-4070-9DA0-48B6F86551C3",
     "client_secret": "q3dpHpYtDrH-KmGD4HMn5OTEx6IsZPBokQ8CqMONWqMSEePWy9bXd3Ua3KvO7f6C"
    }'
    

    The response of this call looks like this:

    JSON
    {
     "token": "SFMyNTY.g2gDYSFuBgCaSXELfgFiAAFRgWnBcvEfet1jIr9OPF984RGTKu-8HcHPQKJitk_kJKiU",
     "valid_for": 6000
    }
    
  3. Create a checkout with details from your order as in the Simple Payment example, but with a special parameter mode and value store_card. It's a POST HTTP call with a JSON body. The call must also contain an Authorization header with the Bearer token from the previous step

    Command Line
    curl --location --request POST 'https://sandbox.payout.one/api/v1/checkouts' \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer SFMyNTY.g2gDYSFuBgCaSXELfgFiAAFRgA.WnBcvEfet2jJr4OPF984RGTKu-8HcHPQKJitk_kJKiU' \
    --header 'Accept: application/json' \
    --header 'Idempotency-Key: 74775d02-745f-4198-cf3c-be9f1971dabe' \
    --data-raw '{
        "amount": "300",
        "currency": "EUR",
        "iban": "SK5511000000002611391222",
        "mode": "store_card",
        "customer": {
            "first_name": "John",
            "last_name": "Doe",
            "email": "[email protected]",
            "phone": "123-4567890"
        },
        "billing_address": {
            "name": "John Doe",
            "address_line_1": "Billing Address Line 1",
            "address_line_2": "Billing Address Line 2",
            "city": "Billington",
            "postal_code": "BL92883",
            "country_code": "GB"
        },
        "shipping_address": {
            "name": "John Doe",
            "address_line_1": "Shipping Address Line 1",
            "address_line_2": "Shipping Address Line 2",
            "city": "Shippington",
            "postal_code": "W153KF",
            "country_code": "GB"
        },
        "products": [
            {
                "name": "Product 1",
                "unit_price": 100,
                "quantity": 3
            }
        ],
        "external_id": "74775d02-745f-4198-cf3c-be9f1971dabe",
        "nonce": "1474e979-9f64-012a-6d8a-f00957d4a4a0",
        "metadata": {
            "note": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been."
        },
        "redirect_url": "https://some-eshop.local/merchant_redirect_url",
        "signature": "ef30790284ffb097e7e4b0d1162db605f97f52c59f0cfc877870bde4e61f7d77"
    }'
    

    Note

    Amount is in cents (EUR), so 3 EUR is 300. It's the same for other currencies; for example, 300 CZK is 30000.

    The signature is generated from a string with this pattern:

    Code
    amount|currency|external_id|nonce|client_secret
    

    For this specific request:

    Code
    300|EUR|74775d02-745f-4198-cf3c-be9f1971dabe|1474e979-9f64-012a-6d8a-f00957d4a4a0|q3dpHpYtDrH-KmGD4HMn5OTEx6IsZPBokQ8CqMONWqMSEePWy9bXd3Ua3KvO7f6C
    

    This string is hashed with SHA256 and encoded with Base16 to this form:

    Code
    ef30790284ffb097e7e4b0d1162db605f97f52c59f0cfc877870bde4e61f7d77
    

    Note

    Some algorithm implementations generate output in UPPERCASE form, so please change all characters to lowercase.

  4. After a successful payment, two types of webhooks are sent:

    • checkout.succeeded
    JSON
     {
      "data": {
        "id": 32222,
        "amount": 300,
        "object": "checkout",
        "status": "succeeded",
        "is_status_final": true,
        "payment": {
          "fee": 35,
          "net": 1535,
          "object": "payment",
          "status": "successful",
          "created_at": 1662716838,
          "failure_reason": "",
          "payment_method": "PayU"
        },
        "currency": "EUR",
        "customer": {
          "email": "[email protected]",
          "last_name": "John",
          "first_name": "Doe",
          "card_number_masked": ""
        },
        "metadata": null,
        "external_id": "9207dd00-d8f1-475a-a317-1067b487fdd6",
        "redirect_url": "https://example.com"
      },
      "type": "checkout.succeeded",
      "nonce": "UzhER2lFOFZCNkNQVmNuNQ",
      "object": "webhook",
      "signature": "b95494dd09183b7cbca40f356d7s4f567sdf765sdf79e1f4a95e936",
      "external_id": "9207dd00-d8f1-475a-a317-1067b487fdd6"
    }
    
    • payu_token.created - contains card_mask and token for recurrent payments
    JSON
     {
      "data": {
        "object": "payu_token",
        "card_mask": "444405******1111",
        "checkout_id": 32222,
        "token_value": "QTEyOEdDTQ.IuWl453sdfsdfsdf8DJRuXdJetbTXA8-vRQWxJYm6zkXB5O0Vxuok019V8.ool6VIXh-u-9dy_C._n2ioCHjys3teQ8WmEM5W08ESwwXTjT0mpLdiLZdLwhJjhbtTW33HdKbNAZFfdgdfg4erggre345a-e9KamwQzXW0_lK8vw.YTYfmlJ65UkVSMa9uXhgLw"
      },
      "type": "payu_token.created",
      "nonce": "UTdsUHJBMnhIaklnS254Ng",
      "object": "webhook",
      "signature": "44444cba7039ab5d6ca048b46016f225db66cd29711fbf9023e0e6c27cfc10f1",
      "external_id": "9207dd00-d8f1-475a-a317-1067b487fdd6"
    }
    
  5. With the received recurrent token from the webhook, you can now make a recurrent payment with the saved card. It's basically identical to the previous request for checkout creation. You have to change the checkout parameter mode to the value recurrent and add an additional required parameter recurrent_token with the value from the payu_token.created webhook.

  6. After a successful recurrent payment, a checkout.succeeded webhook is sent.

Test cards

Number Month Year CVV 3DS result Behavior
4245757666349685 12 29 123 challenge required Positive authorization
5150030090350186 12 29 123 3DS Method required and then successful frictionless Positive authorization
4012001037141120 12 29 123 3DS Method and challenge required Positive authorization
5100052384536834 12 29 123 challenge params if sdk object sent in OrderCreateRequest Positive authorization
5100052384536818 02 32 123 challenge required / if no 3DS is used, returns soft decline (SSD) Positive authorization
5100052384536826 12 29 123 frictionless positive authentication Positive authorization
5521455186577727 12 29 123 frictionless negative authentication no authorization (authentication fails)

Was this page helpful?