# Coinvay PHP kit · 1.2.0 PHP 8.1+, cURL and PDO SQLite. This is a server library + integration endpoints for your existing application, not a complete standalone shop. ## Connect your application 1. Keep `src/`, `bootstrap.php`, `reconcile.php`, secrets and SQLite outside the document root. Mount only `public/` scripts through your PHP application. Serve HTTPS. 2. Set the environment variables in config.env.example using your hosting secret controls. The scripts read real environment variables; the example file is not automatically loaded. Create a private writable directory for COINVAY_ORDER_DB, restrict it to your application user, and back it up with SQLite's backup mechanism or a quiescent copy including WAL state. 3. Reuse your existing authenticated PHP session. After login, set `$_SESSION['user_id']` to the authenticated application's user ID and `$_SESSION['csrf']` to a random token. Never set the user ID from customer input. Render the CSRF token for the authenticated page. 4. At your trusted server's order-creation step, insert your order with a unique reference and integer minor units in the original currency (the legacy column is named `cents`) into the `orders` table using a prepared statement. `owner` must be your authenticated user ID. Example below. Do not let the browser insert arbitrary prices. 5. Send `POST /checkout.php` with JSON `{ "orderId": "your-order-id" }`, the session cookie and `X-CSRF-Token`. Return/redirect to `checkoutUrl`. The gateway API key stays on the server. A second request reuses the invoice. 6. Configure Coinvay postback `/webhook.php` + signing secret if your plan includes webhooks. Also schedule `php /private/path/reconcile.php` once per minute. The cursor processes 20 invoices per run and rotates through the backlog. With no webhooks, payment timing follows polling. 7. `GET /status.php?orderId=...` uses the logged-in user's order ownership. It reads confirmed local state, not a customer-supplied paid flag. 8. A confirmed payment atomically writes `orders.paid=1` and **one `outbox` row**. Your delivery worker must consume outbox rows idempotently using order_id as its unique delivery key, then set completed=1. This kit cannot know how your business delivers goods. A server-confirmed paid status is not proof your downstream delivery worker finished. Trusted order insertion (run inside your backend after loading the real cart): ```php require '/private/coinvay/bootstrap.php'; $stmt = $store->db->prepare('INSERT INTO orders(id,owner,reference,cents,email,name,currency) VALUES(?,?,?,?,?,?,?)'); $stmt->execute([$orderId, $authenticatedUserId, $uniqueStoreOrderReference, $trustedMinorUnits, $email, $name, $trustedCurrency]); ``` For example, AED 367.25 is `cents=36725, currency="AED"`; JPY 100 is `cents=100, currency="JPY"`; KWD 1.005 is `cents=1005, currency="KWD"`. Use `Client::minor($trustedPrice,$trustedCurrency)` to parse. The constructor safely adds `currency` (default USD for old orders) and `usd_cents` to existing kit databases. Checkout sends the original total to Coinvay, which returns a locked USD total. Reconciliation checks both totals. Use `Client::create($reference,$minorUnits,$email,$name,$currency)` for the standalone client. Do not mutate a saved order reference/total after creating its invoice. Cancel or review the payment separately when a business order changes. Native Coinvay API access and plan limits apply. ## Staging acceptance Use two different user sessions to verify order isolation. Check missing CSRF, unauthorized order, wrong total/currency, stale/bad HMAC, unpaid API status, concurrent/replayed callbacks, API downtime and delayed confirmation. Verify exactly one outbox row after webhook+poll overlap. Test your own delivery worker and backups. No credentials or real orders are included. ## Branding The updated Coinvay logo assets and usage instructions are included in [BRANDING.md](BRANDING.md). Use SVG on supported web surfaces and PNG for native/platform restrictions. `public/example.html` illustrates branded checkout. Integrate its markup into your authenticated application template and supply `window.authorizedCoinvayOrder = {orderId, csrfToken}` using your server's safe JSON serialization, after verifying the user's ownership. Keep the API key on the server. The example remains disabled without that context and never accepts a browser-provided amount. ## Manual or automatic account connection · 1.2.0 Use **Connect to Coinvay** to sign in and authorize this store, or retain manual API-key setup. This release adds separate checkout business name/logo and per-store signed webhooks without changing other stores. Read **CONNECT.md**, included in this package, for exact controls, environment variables, administrator-session integration, encryption/backups, permissions and staging checks. Custom app kits require your existing administrator authentication; Shopify remains subject to platform approval.