Background
The backend needs a public (unauthenticated) endpoint that resolves an invoice by its paymentSlug and returns the information a customer needs to complete payment, without exposing sensitive merchant or internal data.
Proposed Steps
- Create
GET /pay/:slug (public) — resolve an invoice by paymentSlug, return safe public view: slug, description, amount, token, status, merchantName, expiresAt, pricingMode
- Return
404 if slug not found
- Return
410 Gone if invoice status is CANCELLED, PAID, or REFUNDED
- Return
410 Gone with { reason: "expired" } if expiresAt is in the past
- Create
POST /pay/:slug/confirm (public) — accept { payerAddress: string, txHash?: string }, create a PaymentConfirmation record (informational only — actual state driven by on-chain events)
Acceptance Criteria
GET /pay/:validSlug on a PENDING invoice → 200 with public invoice data
- Merchant business name is included in the response
GET /pay/:slug on unknown slug → 404
GET /pay/:slug on CANCELLED/PAID invoice → 410
GET /pay/:slug on expired invoice → 410 { reason: "expired" }
POST /pay/:slug/confirm stores the confirmation and returns 202
- No auth required on either endpoint
- No sensitive merchant or internal fields are exposed
Background
The backend needs a public (unauthenticated) endpoint that resolves an invoice by its
paymentSlugand returns the information a customer needs to complete payment, without exposing sensitive merchant or internal data.Proposed Steps
GET /pay/:slug(public) — resolve an invoice bypaymentSlug, return safe public view:slug,description,amount,token,status,merchantName,expiresAt,pricingMode404if slug not found410 Goneif invoice status isCANCELLED,PAID, orREFUNDED410 Gonewith{ reason: "expired" }ifexpiresAtis in the pastPOST /pay/:slug/confirm(public) — accept{ payerAddress: string, txHash?: string }, create aPaymentConfirmationrecord (informational only — actual state driven by on-chain events)Acceptance Criteria
GET /pay/:validSlugon a PENDING invoice →200with public invoice dataGET /pay/:slugon unknown slug →404GET /pay/:slugon CANCELLED/PAID invoice →410GET /pay/:slugon expired invoice →410 { reason: "expired" }POST /pay/:slug/confirmstores the confirmation and returns202