Skip to content

Instantly share code, notes, and snippets.

@ricbermo
Created August 5, 2026 15:44
Show Gist options
  • Select an option

  • Save ricbermo/c3f4f3b0980013dd93e6c4cfeb3cad03 to your computer and use it in GitHub Desktop.

Select an option

Save ricbermo/c3f4f3b0980013dd93e6c4cfeb3cad03 to your computer and use it in GitHub Desktop.
Verify P2 mobile wire contract and active-method semantics

P2 Mobile Wire Contract

Research ticket: mobile#2
Sources frozen: product-api PR #105 head 294afa6, 2026-08-05.

Resolution

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.

Endpoints

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.

States And Errors

  • Payment statuses: pending, approved, declined, failed. Only declined and failed can start another attempt. pending and approved block duplicates. P2 state contract
  • Service canceled_unpaid is terminal. Mobile must disable chat, reassignment, and payment retry. payment_deadline_at is 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

Active-Method Finding

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.

Current Mobile Reconciliation

  • api/services.ts creates requests with client price: 5000 and payment_method_id; P2 rejects client price and moves method selection to atomic assignment. mobile source, P2 creation contract
  • selectNurseRequest sends only { service: { account_id } }; P2 requires payment_method_id in same update. mobile source
  • Mobile defines /account_patient/payments and /account_patient/payment_methods, but no payment mutation client or P2 payment/service state types were found. payment endpoint, method endpoint
  • usePaymentMethods passes server collection through without active filtering. Do not add client filtering from unsupported fields. hook

Implementation Gate

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment