Subscriptions

Introduction

Subscriptions allow you to have a long term billing relationship with your customers. You can in one payment process ask for a one time fee (a payment) plus an authorization to charge your customer in the future without requiring to come back to your website or take any action. As part of the checkout flow your customer authorizes you to debit it via the ProCheckout API up to a total amount every frequency periods. Allowed periods are DAY, WEEK and MONTH.

For instance, in the example below you get authorization to debit up to 22.3 EUR each month. You can create as much charges as you need against this subscription but you can’t exceed your authorization within the given period. So if on 2025-09-02 you issue a 15 EUR charge and on 2025-09-24 you issue a 6 EUR charge, a 2 EUR charge on 2025-09-30 would not be authorized but on 2025-10-01 you would be allowed to issue a 22.3 EUR charge.

start_date is when you can issue the first charge against this subscription. ext_subscriptionid is your identifier for this particular subscription, equivalent to ext_invoiceid in payments.

In this example we ask for a subscription without an independent initial payment. If you require a separate payment such as a setup fee you can generate a checkout with both payment and subscription objects such as:

 "payment": {...},
 "subscription": {...},
 "url_confirm": "http://...",
 "url_cancel": "http://..."

In this case both payment and subscription are processed as a single checkout so either both successed or fail.

For a simple 22.3 EUR subscription every month you would send

  curl https://services.wallet.pt/api/v2/checkout \
  -H "Content-Type: application/json" \
  -H "Authorization: WalletPT 7a0eb41208209639eda9bf765b6cb04d59fb9e34" \
  -d '{
    "subscription": {
        "amount": 22.3,
        "currency": "EUR",
        "frequency": 1,
        "period": "MONTH",
        "start_date": "2025-09-03",
        "end_date": "2025-12-31",
        "description": "Socks magazine subscription",
        "ext_subscriptionid": "mag-2-xx45"
    },
    "url_cancel": "https://example.com/shop/cancel",
    "url_confirm": "https://example.com/shop/confirm"
  }'

MEO Wallet returns:

{
    "date": "2025-03-27T15:18:09+0000",
    "id": "81ae8d9a-f03a-42f8-8464-442a679d13db",
    "merchant": {
        "email": "support@shoppp.pt",
        "id": 1443,
        "name": "Shoppp"
    },
    "subscription": {
        "amount": 22.3,
        "currency": "EUR",
        "description": "Socks magazine subscription",
        "end_date": "2025-12-31",
        "ext_subscriptionid": "mag-2-xx45",
        "frequency": 1,
        "id": "fc1abf2d-31ba-46de-8996-d370d0f42441",
        "period": "MONTH",
        "start_date": "2025-09-01",
        "status": "NEW"
    },
    "url_cancel": "https://example.com/shop/cancel?checkoutid=81ae8d9a-f03a-42f8-8464-442a679d13db",
    "url_confirm": "https://example.com/shop/confirm?checkoutid=81ae8d9a-f03a-42f8-8464-442a679d13db",
    "url_redirect": "https://wallet.pt/checkout/81ae8d9a-f03a-42f8-8464-442a679d13db"
}

You should retain the subscription id as it allows you to create charges against this subscription and progress as usual on the ProCheckout flow and redirect the customer to url_redirect. When the customer authorizes or declines the subscription you will get a callback.

Below, you can see a callback example of an authorized subscription:

{
  "event": "APPROVED",
  "subscription_id" : "fc1abf2d-31ba-46de-8996-d370d0f42441",
  "ext_subscriptionid": "mag-2-xx45",
  "subscription_end_date": "2025-12-31"
}

If your subscription has an one time fee, you will get a callback related with the payment operation too. The structure is documented here.

Please note: If the customer accepts the subscription using a credit card, the subscription end date can change, depending on the credit card validity date. The new subscription end date will be returned on a callback sent when this occurs.

Charging a subscription

To create a charge against a subscription you POST a payment object to /api/v2/subscriptions/:id/charge. In this example we charge 22 EUR against the subscription created above.

  curl https://services.wallet.pt/api/v2/subscriptions/fc1abf2d-31ba-46de-8996-d370d0f42441/charge \
  -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: WalletPT 7a0eb41208209639eda9bf765b6cb04d59fb9e34" \
  -d '{
    "payment": {
        "amount": 22,
        "client": {
            "address": {
                "address": "Av. Fontes Pereira de Melo",
                "city": "Lisboa",
                "country": "pt",
                "postalcode": "1100-000"
            },
            "email": "jsantos@email.com",
            "name": "John Santos"
        },
        "currency": "EUR",
        "ext_invoiceid": "mag-set2025-xxd3fs",
        "items": [
            {
                "descr": "September Socks Magazine",
                "name": "Socks Magazine",
                "qt": 1,
                "ref": 4325
            }
        ]
    }
  }'

Which returns immediately an object with the new charge id.

{
    "amount": 22,
    "currency": "EUR",
    "ext_invoiceid": "mag-set2025-xxd3fs",
    "id": "ffcda661-ae48-4bb0-bf43-15f810860f04",
    "status": "NEW",
    "subscription_id": "fc1abf2d-31ba-46de-8996-d370d0f42441"
}

As with other payments processing is asynchronous and when the charge has been processed you will get a callback with the result of the payment.

This is an example of a callback for a successful payment of the above charge.

{
    "amount": 22,
    "charge_order_id": "ffcda661-ae48-4bb0-bf43-15f810860f04",
    "currency": "EUR",
    "event": "COMPLETED",
    "ext_invoiceid": "mag-set2025-xxd3fs",
    "ext_subscriptionid": "mag-2-xx45",
    "subscription_id": "fc1abf2d-31ba-46de-8996-d370d0f42441"
}

Subscriptions life cycle

Subscriptions always start as NEW before being authorized. If you want to create a subscription without an end_date, omit this field in your request.

They then progress to either APPROVED or FAILED depending on user acceptance. An APPROVED subscription is active and will accept charges.

A subscription will naturally progress to EXPIRED after its end_date (which can be changed according to the payment method used on it).

If the subscription is canceled by the customer it goes to CANCELED state. You the merchant can also cancel a subscription you no longer require in which case the subscription will be VOIDED. EXPIRED, VOICED and CANCELED are final states and charges against subscription in these states will fail.

The following table sumarizes subscription states.

State Description
NEW The subscription has not been accepted yet
APPROVED The subscription has been accepted by the customer
FAILED The subscription could not be activated via user action
EXPIRED The subscription is no longer active because it’s past its end_date
VOIDED The subscription was cancelled by the merchant (you)
CANCELED The subscription was cancelled by the customer

State changes to APPROVED, FAILED and CANCELED trigger callbacks such as

{
  "event": "CANCELED",
  "subscription_id" : "fc1abf2d-31ba-46de-8996-d370d0f42441",
  "ext_subscriptionid": "mag-2-xx45",
  "subscription_end_date": "2025-12-31"
}

You should manage your subscriptions. Repeated charges against inactive subscriptions will always fail and will be considered bad customer relationship management.

Subscriptions and charges are collections

MEO Wallet adheres to the REST collections pattern and both subscriptions and charges are collections you can GET, POST and DELETE the collection or members as described below.

Structures

Subscription
Field Type In/Out Mandatory Description
id string O Y subscription id
amount number I Y authorization limit
currency string I Y currency (only EUR supported)
frequency integer I Y number of billing periods (1 to 365)
period string I Y billing period (DAY, WEEK, MONTH)
start_date date I Y subscription start
end_date date I O subscription end
ext_subscriptionid string I O merchant reference for this subscription
description string I O optional description
Charge Order
Field Type In/Out Mandatory Description
id string O Y charge order id
subscription_id string O Y subscription id
amount number O Y charged amount
currency string O Y currency (only EUR supported)
ext_invoiceid string O Y merchant reference for this charge
status string O Y charge order status
Subscription Callback
Field Type In/Out Mandatory Description
event string O Y subscription status change
subscription_id string O Y subscription id
ext_subscriptionid string O Y subscription id
subscription_end_date date O Y subscription end date
Charge Order Callback
Field Type In/Out Mandatory Description
event string O Y charge order status change
charge_order_id string O Y charge order id
amount number O Y charged amount
currency string O Y currency (only EUR supported)
subscription_id string O Y subscription id
ext_subscriptionid string O Y merchant reference for this subscription
ext_invoiceid string O Y merchant reference for this charge

Get subscription

Request GET /api/v2/subscriptions/:id
URL params Subscription id
Data params none
Returns Subscription

Get subscriptions

Gets all subscriptions with optional date range and pagination.

Request GET /api/v2/subscriptions
Query params limit=[int], offset=[int]
Data params none
Returns Subscription Array
{
  "elements" : [
    "subscription": {
      "id": UUID,
      "amount":DOUBLE,
      "currency":"EUR",
      "start_date": DATE,
      "end_date": DATE,
      "description" : STRING,
      "status": (NEW|APPROVED|FAILED|EXPIRED|VOIDED|CANCELED),
      "default_payment_method" : (WALLET|CC)
      "card" : {...}
    },
    "subscription":{...},
    "subscription":{...},
    ...
  ],
  "total" : "14"
}

Delete subscription

Destroys a subscription progressing it to VOIDED state.

Request DELETE /api/v2/Subscriptions/:id
URL params subscription id
Data params none
Returns Subscription

Get charges for a subscription

Gets all charges against a specific subscription with optional date range and pagination.

Request GET /api/v2/subscriptions/:id/charge
Query params limit=[int], offset=[int]
Data params none
Returns Charge Array
{
  "elements" : [
    "charge_order" : {
      "id" : UUID,
      "subscrition_id" : UUID,
      "amount" : DOUBLE,
      "currency" : "EUR"
      "date" : DATE,
      "status" : (NEW|PROCESSING|FAIL|SUCCESS),
    },
    "charge_order" : {...},
    "charge_order" : {...},
    "charge_order" : {...},
    ...
  ],
  "total" : "121"
}

Charge status is one of the following

Charge status Description
NEW The charge request passes basic validation and has been accepted
PROCESSING The charge is being processed using the customer authorized payment methods
FAIL The charge could not be completed because the customer has insufficient funds or other similar reason
SUCCESS The charge was successful and your wallet was credited with the payment

Get charge

Get a charge by id

Request GET /api/v2/subscriptions/:id/charge/:charge_id
URL params subscriptions id, charge id
Data params none
Returns Charge Order

Create a charge

Request POST /api/v2/subscriptions/:id/charge
URL params none
Data params Payment
Returns status object