Notes

Orders and payment links

A payment link pays one order, once. The mistakes are in the seams: a payer who comes back to the checkout, a success page that is taken as proof, a payment for less than the order, and a link that is still open when it should not be.

Create the link when the payer clicks Pay, and store its "url" with the order, and in v2 its "id" too. If the payer comes back to your checkout, as after pressing back in the browser, send them to the same link: it keeps its state on our servers, and can be paid only once.

A second link for the same order is a second payment that can go through. Two links for one order, both paid, are two transactions with the same "orderid", and one of them has to be refunded. So create a new link only when the old one can no longer be paid:

  • It expired. Its "lifetime" is up, which you know from when you created it.
  • In v2, you deleted it, because the order changed: delete first, then create the new link.

In v1, a link can't be deleted, so a link that is out there can be paid until it expires. Give each link a "lifetime" no longer than the payer needs.

The order ID

Give each order an "orderid" that no other order of yours has. It is how you match the transaction to the order when seq returns it, and the reference that the payer's bank and your acquirer see. v1 lets you leave it out, and v2 does not: in both, always send it, as a string. If an order can be paid in parts, or paid again after a link expired, the transactions share its "orderid": match them by their "id", which seq returns, and sum them.

The success page is no proof

The payment window sends the payer to your "successurl" when they have paid, without adding anything to it. So:

  • Anyone can open it, paid or not. Never mark an order as paid because the payer reached it: mark it when seq returns the transaction.
  • The payer can reach it before seq returns the transaction, and the ping may come a moment later. Look the order up, and if it is not paid yet, synchronize once before you say anything. See the success page.
  • The payer may never reach it, if they close the browser after paying. The order is paid all the same, and seq tells you.

Put what the page needs in its URL, such as https://shop.example/thanks?order=1234zx, as we add nothing.

What was authorized

In v1, a partial authorization is accepted: a bank that approves less than the link's total, as some prepaid cards do, makes a transaction for what it approved. Compare the transaction's totals.authorized with the order before you deliver it, and treat a shortfall as unpaid, or ask the payer for the rest. See The transaction object.

In v2, a partial authorization is declined, and the payer can try again, so a transaction is always for the link's whole total.

Sometimes paying a link has become wrong:

  • The payer paid another way, such as by bank transfer.
  • What it was for is gone, such as the last seat on a bus.
  • The order changed, so the amount is wrong.

In v2, delete the link. Deleting is final. If the payer is paying the link at that moment, the delete waits for their bank's answer, and fails with 409 link is paid if the bank authorized the payment. Then the order is paid after all: deliver it, or void the transaction when seq returns it.

In v1, there is no request to stop a link, so plan for a payment that comes anyway. Mark the order so that a payment for it is not delivered, and when seq returns its transaction, don't capture it: the payer's bank releases the held amount when the authorization runs out. If it was captured, as with "autocapture", refund it. A short "lifetime" keeps the window for this small.

A declined payment is not an error, and you hear nothing of it: the payer sees the decline in the payment window and can try again until the link expires. Seq returns a transaction only when a payment succeeds, so a link that expires unpaid leaves no trace in seq.

To follow up on abandoned checkouts, keep the time each link expires, and treat an order whose link expired without a transaction as abandoned.