Build payments into your product with TPE virtual. Start integrating →
Logo

Create a payment plan

Agree a schedule of instalments with one customer, and follow what they pay.

A payment plan splits a total into dated instalments for one customer (paiement par facilité). You create it under a payment instance of your account that's ready and active. Your token needs the plans:write scope, and plans:read to read plans afterwards.

The customer must use a MyTPE account to pay a plan. MyTPE opens one for their email address if it has none. To collect a payment from a customer who won't use an account, create a payment link instead: anyone with the URL can pay it, but it doesn't follow instalments.

  1. Optional: ask MyTPE to propose a schedule. Nothing is saved.

    curl -X POST https://api.mytpe.app/api/ext/plans/preview \
      -H "Authorization: Bearer $MYTPE_ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "total_amount": 30000,
        "count": 3,
        "first_due_on": "2030-01-15"
      }'

    The response lists each instalment's due_on and amount, and they add up to the total. To take a first payment before the instalments, add deposit and deposit_due_on. To space the instalments out, add every_months.

  2. Create the plan with the schedule you agreed. The instalment amounts must add up to total_amount. Send an Idempotency-Key so that a retry can't create a second plan and send a second invitation.

    curl -X POST https://api.mytpe.app/api/ext/plans \
      -H "Authorization: Bearer $MYTPE_ACCESS_TOKEN" \
      -H "Idempotency-Key: tuition-2030-customer-1" \
      -H "Content-Type: application/json" \
      -d '{
        "payment_instance_id": "your-instance-id",
        "title": "Tuition 2030",
        "reference": "your-reference",
        "total_amount": 30000,
        "customer_name": "Your customer",
        "customer_email": "customer@example.com",
        "installments": [
          { "due_on": "2030-01-15", "amount": 10000 },
          { "due_on": "2030-02-15", "amount": 10000 },
          { "due_on": "2030-03-15", "amount": 10000 }
        ]
      }'

    The plan's status is active. MyTPE opens an account for the customer if their email address has none, and emails them an invitation.

  3. The customer pays. They sign in on MyTPE with that email address and choose how much to pay, from minimum_payment up to remaining. Nobody else can pay toward the plan, so don't share its pay_slug as a payment link.

  4. Follow the plan. Read it with GET /plans/{id}, or list the plans that need attention with GET /plans?status=late.

    curl https://api.mytpe.app/api/ext/plans/your-plan-id \
      -H "Authorization: Bearer $MYTPE_ACCESS_TOKEN"

    A payment is settled against the oldest unpaid instalment first. The plan's balance changes shortly after the payment, and the payment appears in payments with its transaction_id.

    To hear about a payment, listen for the payment_link.paid webhook event. A plan is paid through a link of its own, so match the slug of the event's payment_link to the plan's pay_slug, then read the plan for its balance. You also receive the other payment_link.* events for that link.

Manage a plan

ActionEndpointEffect
Send a reminderPOST /plans/{id}/remindEmails the customer about the next unpaid instalment. Limited to 10 calls a minute.
CancelPOST /plans/{id}/cancelEnds an active plan. What was paid stays recorded, and nothing more can be paid.

You can't change a plan's schedule after you create it. To change it, cancel the plan and create another.

While a plan is active, its link and its payment instance stay as they were agreed:

  • POST /links/{id}/pause, POST /links/{id}/archive and a PUT /links/{id} that changes the amount, usage or dates answer 422 with PAYMENT_LINK_HELD_BY_PLAN.
  • DELETE /instances/{id} answers 422 with PAYMENT_INSTANCE_HAS_ACTIVE_PLANS.
  • Changing who gets paid answers 422 with PAYMENT_PAYEE_HELD_BY_PLAN. That covers the instance's identification, bank account and acquiring mode, and editing or deleting that bank account or identification.

Cancel the plan first. You can still rename the instance.

If the instance is suspended

MyTPE staff can suspend an instance while plans are active. The plan keeps its status and schedule, and nothing moves to another instance. Until the instance is reactivated:

  • The plan's payment_blocked_reason is instance_suspended, and the customer can't start a payment.
  • MyTPE emails your customer once to say that payment is temporarily unavailable, without saying why.
  • MyTPE doesn't send reminders, and POST /plans/{id}/remind answers 422 with PAYMENT_PLAN_INSTANCE_CANNOT_COLLECT.
  • A payment already at the gateway is still recorded.
  • You can still cancel the plan.

Due dates don't move. Instalments that pass their due date in that time still show as late.

When the instance is reactivated, payment_blocked_reason is null again, MyTPE emails your customer once to say that they can pay again, and payments and reminders resume. You don't need to do anything.

Limits on new plans

A new plan can open an account for your customer and sends them an email, so POST /plans has limits of its own on top of the rate limits. They count plans per day for your integration, your account and each recipient, and new customer accounts per day. Over a limit, the API answers 429 with Retry-After, and nothing is created or sent.

For the status values, see Statuses and enums. For every field, see Payment plans.

On this page