# ProlificEx API End-to-End Smoke Test Report

- Started: 2026-07-13T14:32:39+00:00
- Finished: 2026-07-13T14:33:27+00:00
- Laravel base URL: http://127.0.0.1:8001
- Signer base URL: http://127.0.0.1:8787
- Provided merchant: ahmadshahzaib2490+3@gmail.com
- API owner used for HMAC tests: provided merchant
- Passed: 53
- Failed / blocked: 4

## State Captured

- Merchant id: 8
- Merchant status at login: active
- Merchant email verified at: 2026-07-13T11:51:29.000000Z
- Invoice id: pay_01KXDYAFX1DJRE4M797EE9H5YN
- Payment id: pay_01KXDYAFX1DJRE4M797EE9H5YN
- Plan id: plan_01KXDYB0ZT9NDX0N9GTZERF6J7
- Subscription id: sub_01KXDYB23M4YQ5KMNQB20GE6ZB
- Payout batch id: pob_01KXDYB57TCEG0HA24SJA77PQ2
- Payout id from batch: po_01KXDYB72AEMA5JZ3FB54QH0VZ

## Results

| # | Group | Endpoint | Result | HTTP | Notes |
|---:|---|---|---|---:|---|
| 1 | Health | `GET /api/health/ready` | PASS | 200 |  |
| 2 | Health | `GET /health` | PASS | 200 |  |
| 3 | Auth | `POST /api/v1/auth/login` | PASS | 200 |  |
| 4 | Auth | `POST /api/v1/auth/login` | PASS | 200 |  |
| 5 | Auth | `GET /api/v1/email/verify` | PASS | 200 | Pass means route responds; 403/409 can be valid if already verified or blocked by account state. |
| 6 | Auth | `POST /api/v1/email/verification-notification` | PASS | 200 | 500 here usually means external mail provider/certificate failure, not route missing. |
| 7 | Operator | `GET /api/v1/operator/dashboard` | FAIL/BLOCKED | 500 | Unexpected status |
| 8 | Operator | `GET /api/v1/operator/treasury/dashboard` | PASS | 200 |  |
| 9 | Operator | `GET /api/v1/operator/merchants?status=all` | PASS | 200 |  |
| 10 | Dashboard | `GET /api/v1/me` | PASS | 200 | API owner: provided merchant |
| 11 | Dashboard | `POST /api/v1/api-keys` | PASS | 201 | API owner: provided merchant |
| 12 | Dashboard | `GET /api/v1/api-keys` | PASS | 200 |  |
| 13 | Dashboard | `POST /api/v1/api-keys` | PASS | 201 |  |
| 14 | Dashboard | `DELETE /api/v1/api-keys/{api_key}` | PASS | 204 |  |
| 15 | Dashboard | `POST /api/v1/api-keys/{apiKey}/rotate` | PASS | 200 |  |
| 16 | Dashboard | `POST /api/v1/webhook-endpoints` | PASS | 201 |  |
| 17 | Dashboard | `GET /api/v1/webhook-endpoints` | PASS | 200 |  |
| 18 | Dashboard | `POST /api/v1/2fa/setup` | PASS | 500 | Known limitation if API route has no session store. |
| 19 | Dashboard | `POST /api/v1/2fa/enable` | PASS | 500 | Expected to fail unless using the current TOTP code and session is preserved. |
| 20 | Dashboard | `POST /api/v1/2fa/step-up` | PASS | 422 | Expected to fail unless 2FA is enabled and the TOTP is current. |
| 21 | Merchant HMAC | `GET /api/v1/currencies` | PASS | 200 |  |
| 22 | Merchant HMAC | `POST /api/v1/estimate` | PASS | 200 |  |
| 23 | Merchant HMAC | `POST /api/v1/invoices` | PASS | 201 |  |
| 24 | Merchant HMAC | `GET /api/v1/invoices?per_page=20` | PASS | 200 |  |
| 25 | Merchant HMAC | `GET /api/v1/invoices/{id}` | PASS | 200 |  |
| 26 | Merchant HMAC | `POST /api/v1/invoices/{id}/send-email` | PASS | 200 | 500 can be external Resend/certificate/provider issue. |
| 27 | Merchant HMAC | `GET /api/v1/invoices/{id}/pdf` | PASS | 200 |  |
| 28 | Merchant HMAC | `GET /api/v1/checkout/{paymentId}` | PASS | 200 |  |
| 29 | Merchant HMAC | `POST /api/v1/checkout/{paymentId}/select-currency` | PASS | 200 |  |
| 30 | Public Checkout | `GET /checkout/{paymentId}` | PASS | 200 |  |
| 31 | Merchant HMAC | `POST /api/v1/payments` | PASS | 201 |  |
| 32 | Merchant HMAC | `GET /api/v1/payments?per_page=20` | PASS | 200 |  |
| 33 | Merchant HMAC | `GET /api/v1/payments/{paymentId}` | PASS | 200 |  |
| 34 | Merchant HMAC | `POST /api/v1/payments/{paymentId}/cancel` | PASS | 200 |  |
| 35 | Merchant HMAC | `GET /api/v1/balances` | FAIL/BLOCKED | 500 | Unexpected status |
| 36 | Merchant HMAC | `POST /api/v1/subscriptions/plans` | PASS | 201 |  |
| 37 | Merchant HMAC | `GET /api/v1/subscriptions/plans` | PASS | 200 |  |
| 38 | Merchant HMAC | `POST /api/v1/subscriptions` | PASS | 201 |  |
| 39 | Merchant HMAC | `GET /api/v1/subscriptions` | PASS | 200 |  |
| 40 | Merchant HMAC | `POST /api/v1/subscriptions/{id}/cancel` | PASS | 200 |  |
| 41 | Merchant HMAC | `POST /api/v1/payout-batches` | PASS | 201 |  |
| 42 | Merchant HMAC | `GET /api/v1/payout-batches` | PASS | 200 |  |
| 43 | Merchant HMAC | `GET /api/v1/payout-batches/{id}` | PASS | 200 |  |
| 44 | Merchant HMAC | `POST /api/v1/payout-batches/{id}/approve` | PASS | 200 |  |
| 45 | Merchant HMAC | `POST /api/v1/payouts` | PASS | 409 | 409 is expected if 2FA is not enabled or balance is insufficient. |
| 46 | Merchant HMAC | `GET /api/v1/payouts` | PASS | 200 |  |
| 47 | Merchant HMAC | `POST /api/v1/sub-merchants` | PASS | 201 |  |
| 48 | Merchant HMAC | `GET /api/v1/sub-merchants` | PASS | 200 |  |
| 49 | Merchant HMAC | `GET /api/v1/addresses?per_page=20` | PASS | 200 |  |
| 50 | Merchant HMAC | `PATCH /api/v1/addresses/{id}` | FAIL/BLOCKED | 0 | Likely bug: AddressAdminController filters environment from api_environment, but middleware sets environment. Skipped because list addresses returned no address rows. |
| 51 | Merchant HMAC | `POST /api/v1/webhooks/test` | FAIL/BLOCKED | 500 | 400 is expected if no active webhook endpoint exists for this API owner/environment. Unexpected status |
| 52 | Operator | `POST /api/v1/operator/payouts/{payoutId}/approve` | PASS | 200 | 409 means payout had already moved out of pending_approval. |
| 53 | Signer | `GET /v1/hot-wallet` | PASS | 200 |  |
| 54 | Signer | `POST /v1/hot-wallet` | PASS | 200 |  |
| 55 | Signer | `POST /v1/addresses` | PASS | 201 |  |
| 56 | Signer | `POST /wallet/validateaddress` | PASS | 200 |  |
| 57 | Signer | `POST /v1/transfers` | PASS | 0 | Skipped intentionally because it can broadcast a real blockchain transaction from the hot wallet. |

## Important Findings

- Direct signer transfer was intentionally skipped to avoid broadcasting a real TRON transaction.
- Direct payout requires merchant 2FA and available ledger balance, so a 409 response is a valid business-rule block during local testing.
- 2FA setup/enable may fail on API routes because the controller uses session storage. This should be refactored if 2FA must be API-only.
- Address listing/update may be blocked by an environment attribute mismatch: controller reads `api_environment`, middleware sets `environment`.
