Research ticket: mobile#2
Sources frozen: product-api PR #105 head 294afa6, 2026-08-05.
P2 wire contract is defined by open, unmerged product-api PR #105. It is not live on product-api main; mobile must treat this as implementation target, not deployed behavior. Contract says server owns pricing, payment state, deadline, compatibility, and duplicate prevention. Mobile refreshes server resources after assignment, bank return/deep link, or notification; it does not run deadline logic or poll ePayco. Contract scope, issue #111.
| Method and path | Request | Success response | Errors / rules |
|---|---|---|---|
GET /v1/account_patient/payment_methods |
None | { payment_methods: [{ id, name, code }] } |
200. Does not expose active. See active-method finding below. controller, view. |
GET /v1/account_patient/services/:service_id/accounts |
Optional filters[payment_method_id], filters[min_price], filters[max_price], filters[id_not_in][], `sort=effective_price asc |
desc` | { accounts: [...] }; each nurse adds price, currency, rate_source, accepted_payment_methods: [{ id, name }]. |
PATCH or PUT /v1/account_patient/services/:id |
{ service: { account_id, payment_method_id } } while service is pending. |
Service response contains id, status, service_time, patient_address, price, base_price, currency, country_code, rate_source, payment_deadline_at, plus existing complement. |
Atomic nurse/method validation. Cash completes assignment without online payment/deadline. Card auto-charges default card. Invalid/missing/unaccepted method is rejected server-side. Missing default card: 422 { errors: [{ message }] }; declined/failed card: 402 { errors: [{ message }], payment }. controller, service view, contract. |
POST /v1/account_patient/payments |
PSE: { payment: { service_id, payment_type: "pse", bank, person_type, description? } }. person_type defaults to natural. Card supports service_id, optional payment_card_id or card, save_card, description; P2 normal path is automatic default-card charge at assignment. |
PSE handoff: 201 { payment }, with payment.status: "pending" and payment.bank_url. Payment fields: id, service_id, payment_type, amount, currency, status, ref_payco, franchise, bank_url, created_at, payment_card. |
Bad PSE input, non-assignable service, missing card, or PSE deadline cutoff: 400 { errors: [{ message }] }. Existing pending/approved PSE: 422 { errors: [{ message: duplicate_attempt }] }. Card declined/failed: 402 with payment. controller, view, request spec. |
GET /v1/account_patient/payments |
None | Payment collection using same payment fields above. | Server-authoritative refresh source. routes. |
- Payment statuses:
pending,approved,declined,failed. Onlydeclinedandfailedcan start another attempt.pendingandapprovedblock duplicates. P2 state contract - Service
canceled_unpaidis terminal. Mobile must disable chat, reassignment, and payment retry.payment_deadline_atis display/refresh data only, not local timer authority. P2 state contract - Required actionable error categories: incompatible method, missing default card, deadline rejection, duplicate pending/approved attempt. Wire shape is
errors: [{ message }]for explicit payment errors; non-payment service validation uses current service validation error handling. Exact translated message text is not stable API vocabulary. issue #111, payment controller
GET /account_patient/payment_methods is not API-guaranteed to return only active methods. Its policy scope is scope.all, its response has no active field, and its request spec creates generic methods and expects every one. Current mobile cannot safely derive active eligibility from this endpoint. Server-side assignment remains authoritative for nurse acceptance, but "active" needs an API change or explicit server confirmation before mobile can enforce it. policy scope, request spec.
Nurse accepted methods are exposed only on candidate service-account results as { id, name }; no code or active marker. The server still rejects a selected method not accepted by that nurse during atomic assignment. candidate view, assignment validation.
api/services.tscreates requests with clientprice: 5000andpayment_method_id; P2 rejects client price and moves method selection to atomic assignment. mobile source, P2 creation contractselectNurseRequestsends only{ service: { account_id } }; P2 requirespayment_method_idin same update. mobile source- Mobile defines
/account_patient/paymentsand/account_patient/payment_methods, but no payment mutation client or P2 payment/service state types were found. payment endpoint, method endpoint usePaymentMethodspasses server collection through without active filtering. Do not add client filtering from unsupported fields. hook
Do not implement against main until product-api PR #105 merges and deploys. Before mobile implementation, obtain a server decision for active-method semantics: filter endpoint to active methods, expose active, or explicitly declare all returned methods selectable. This is sole contract blocker found.