Customer API

Membership Payments

Recover failed membership payments, share payment-method links, and choose billing addresses

These endpoints let an authenticated customer manage payments for their own memberships. Every request requires a JWT bearer token and a linked customer profile. Obtain the membershipId from List Memberships.

Responses use top-level recovery, setup, link, or billingAddress fields rather than a data envelope. Amounts are in minor currency units; timestamps are Unix milliseconds.

Inspect a payment

GET /membership-payments/recovery?membershipId={membershipId}
curl "https://edge.tiquo.app/api/client/v1/membership-payments/recovery?membershipId=membership_123" \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9..."
{
  "success": true,
  "recovery": {
    "membershipId": "membership_123",
    "planName": "Gold Member",
    "state": "requires_payment_method",
    "recoverable": true,
    "invoiceId": "in_123",
    "invoiceStatus": "open",
    "paymentIntentStatus": "requires_payment_method",
    "clientSecret": null,
    "amountDue": 2500,
    "currency": "gbp",
    "invoiceCreatedAt": 1790812800000,
    "nextPaymentAttemptAt": null,
    "failureReason": "expired_card",
    "paymentMethod": {
      "brand": "visa",
      "last4": "4242",
      "expMonth": 9,
      "expYear": 2026
    },
    "canRetrySavedPaymentMethod": true,
    "reconciliationPending": false
  }
}
FieldMeaning
membershipId, planNameThe owned membership and its plan name
stateCurrent state from the table below
recoverableWhether an eligible outstanding invoice can be recovered for this active or suspended membership
invoiceId, invoiceStatus, paymentIntentStatusPayment-provider details; nullable when unavailable
clientSecretStripe confirmation secret when state is requires_action; otherwise null
amountDue, currencyOutstanding amount in minor units and invoice currency; 0 and an empty currency when no invoice is available
invoiceCreatedAt, nextPaymentAttemptAtUnix timestamps in milliseconds, or null
failureReasonauthentication_required, expired_card, insufficient_funds, or payment_failed
paymentMethodSaved-card summary (brand, last4, expMonth, expYear), or null
canRetrySavedPaymentMethodWhether a saved card is available; also check recoverable before offering a retry
reconciliationPendingWhether a paid Stripe invoice still needs reconciliation with Tiquo
StateClient behaviour
requires_payment_methodOffer a saved-card retry when available, or collect a new card
requires_actionUse the returned clientSecret with Stripe's client SDK to complete authentication, then call finalize
processingWait and refresh the recovery state; do not show the invoice as paid yet
paidPayment is paid; check reconciliationPending before treating the Tiquo update as complete
unavailableNo eligible invoice is available for recovery

An HTTP 200 means the request succeeded. It does not mean the invoice has been paid: inspect recovery.state.

Recover a payment

POST /membership-payments/recovery
FieldRequiredDescription
membershipIdYesThe customer's membership ID
operationYesOne of the operations below
setupIntentIdFor confirm_payment_methodSucceeded SetupIntent created by this membership recovery flow
OperationBehaviourResponse field
retryAttempt payment with the saved card; may return a required authentication steprecovery
create_payment_method_setupCreate a card-only SetupIntent for this membership and invoicesetup
confirm_payment_methodSave the confirmed card as the Stripe customer and membership default, then attempt paymentrecovery
finalizeRefresh payment state and reconcile a paid invoice with Tiquorecovery

Retry a saved card

curl -X POST "https://edge.tiquo.app/api/client/v1/membership-payments/recovery" \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9..." \
  -H "Content-Type: application/json" \
  -d '{"membershipId":"membership_123","operation":"retry"}'

The response has the same recovery object as the inspection endpoint. Follow the returned state, including any authentication step.

Replace the card

  1. Send {"membershipId":"membership_123","operation":"create_payment_method_setup"}.
  2. Collect and confirm the new card with Stripe's client SDK using setup.clientSecret.
  3. After the SetupIntent succeeds, send {"membershipId":"membership_123","operation":"confirm_payment_method","setupIntentId":"seti_123"}.
  4. Inspect recovery.state. If it is requires_action, complete the Stripe authentication step and send {"membershipId":"membership_123","operation":"finalize"}.

The setup response is:

{
  "success": true,
  "setup": {
    "setupIntentId": "seti_123",
    "clientSecret": "seti_123_secret_..."
  }
}

This flow accepts cards only. A SetupIntent from the general /payment-methods/setup endpoint, another customer, another membership, or another invoice is rejected. Only a succeeded recovery SetupIntent can be confirmed.

Use finalize after client-side payment confirmation. If the returned state is paid with reconciliationPending: true, retry finalisation later to reconcile Tiquo's membership and order records.

POST /membership-payments/payment-method-link

Create a link the customer can share with another person, such as their company, to supply the membership's payment method. This request creates the link; the customer shares it themselves. It does not send an email.

curl -X POST "https://edge.tiquo.app/api/client/v1/membership-payments/payment-method-link" \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9..." \
  -H "Content-Type: application/json" \
  -d '{"membershipId":"membership_123"}'

The response contains success: true and link: { url, expiresAt }. Use the returned URL unchanged; expiresAt is its expiry time in Unix milliseconds. The membership must belong to the customer and be eligible for a Stripe subscription payment-method update.

Choose a billing address

POST /membership-payments/billing-address

Choose the address used on invoices from the next renewal. Cancelled or expired memberships cannot be updated.

FieldRequiredDescription
membershipIdYesThe customer's membership ID
billingAddressIdNoAn existing address belonging to the customer, with type billing or both
addressNoA new billing address to save on the customer profile

For address, supply non-empty addressLine1, city, postalCode, and country. Optional fields are company, addressLine2, and state. The company is included in the billing address used for the invoice.

curl -X POST "https://edge.tiquo.app/api/client/v1/membership-payments/billing-address" \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "membershipId": "membership_123",
    "address": {
      "company": "Acme Ltd",
      "addressLine1": "10 Example Street",
      "city": "London",
      "postalCode": "SW1A 1AA",
      "country": "GB"
    }
  }'

If both address and billingAddressId are supplied, address takes precedence. An identical saved address is reused where available. A newly saved address becomes the customer's default only when they have no billing address yet.

To restore the default, send only {"membershipId":"membership_123"}. The membership then uses the customer's default billing address, or the first available billing address when none is marked as default.

{
  "success": true,
  "billingAddress": {
    "_id": "address_123",
    "chosen": true,
    "company": "Acme Ltd",
    "addressLine1": "10 Example Street",
    "city": "London",
    "postalCode": "SW1A 1AA",
    "country": "GB"
  }
}

chosen is true when this membership explicitly selects the address and false when it falls back to a customer billing address. Other optional response fields are label, addressLine2, and state. billingAddress is null when no billing address is available. Existing invoices are not rewritten.

Errors

StatusDescription
400Missing or invalid request data, membership unavailable or not owned, an ineligible payment or address, or a payment-provider operation that could not be completed
401Missing, invalid, or expired access token
403No customer profile is linked to the account
409The membership is held in a connected system such as HubSpot (ID starts with ext_, code external_membership) and is managed there

Errors return {"success":false,"error":"Description of what went wrong"}. These membership-payment handlers return 400 for operational failures, including unavailable memberships; do not assume those failures return 404 or 500.

Sur cette page