Platform quickstart
Audience: a developer at a platform (a product like LodgePay or ChurchPay) that wants to take payments on behalf of many tenants under one credential. If you're integrating Movere for your own business, you want the merchant quickstart instead.
A merchant holds one API key scoped to one business. A
platform holds one mk_platform_* key and acts on behalf of any
tenant who has connected to it: each tenant approves you once through
a hosted consent flow, Movere records a grant for the
(platform, merchant, environment) combination. Address the tenant
with a Mooov-Merchant header on ordinary API calls. No grant, no
access. The full contract is the
Connect protocol; this page is the shortest
path through it.
1. Get registered
Platform registration is operator-led. There is no self-serve signup.
Email ops@movere.money with:
- a slug (lowercase, stable, e.g.
churchpay) and a display name (what tenants see on the consent screen) - a security contact email
- your redirect URI allowlist, one or more exact URLs per environment (exact-match only: no path prefixes, no wildcards)
- your platform-wide webhook URL
Movere provisions a platform credential and you receive:
- a platform key id (
mk_platform_*) and its secret, shared once via a 1Password link (24h TTL) - a webhook signing secret for your platform-wide webhook URL
The platform credential spans Test and Live. Merchant grants and
payment data remain environment-scoped. On-behalf-of API requests use
?environment=test or ?environment=live; omission defaults to Live.
Ordinary payment webhooks for platforms currently cover Live only.
Coordinate Test setup and Live readiness with your Movere contact; see
Environments.
2. Sign a request
Same HMAC scheme as merchant keys, plus one header. Your secret is never sent on the wire:
X-Mooov-Key-Id: mk_platform_xxxxxxxx
X-Mooov-Timestamp: 2026-06-12T12:00:00Z (RFC3339 UTC, ±5 min skew)
X-Mooov-Signature: <lowercase hex HMAC-SHA256>
Mooov-Merchant: merch_<id> (required on on-behalf-of calls)
Idempotency-Key: <uuid> (required on writes)
The signature is HMAC-SHA256 over exactly four lines (no trailing newline):
<METHOD>\n<PATH>\n<TIMESTAMP>\n<hex SHA-256 of the raw body, or of "" on GET>
PATH excludes the host and query string. For example, send
/v1/payment_intents?environment=test but sign /v1/payment_intents.
Drop-in signers in Python and TypeScript (with the Mooov-Merchant
header already wired in) are in
§2 of the Connect protocol.
3. Connect your first tenant
Five steps, OAuth-shaped:
You generate a signed
statetoken and send the tenant's browser to the hosted authorize page:https://connect.mooov.money/authorize ?client_id=<your platform slug> &redirect_uri=<your callback URL, exact-match against your allowlist> &state=<your signed CSRF token> &scope=payments:write+payments:read+customers:write &mode=testmode=testcreates a Test grant; usemode=livefor Live. Omission defaults to Live. URL-encode parameter values when building the URL.scopeis OAuth-style space-separated (a+in a query string is a space). Pick scopes from the scopes reference; request only what you need, because widening later means re-prompting the tenant.The tenant signs into Movere (or creates an account), sees your display name and the requested scopes on a consent screen, and clicks Connect.
Movere records the grant and redirects to
<redirect_uri>?code=<auth_code>&state=<your state>. The code is single-use and expires in 10 minutes.You verify
state, then exchange the code with an HMAC-signedPOST /v1/public/connect/token:{ "grant_type": "authorization_code", "code": "<auth_code>", "redirect_uri": "<same redirect_uri as step 1>" }Store
merchant_id,grant_id, andenvironment. These are durable identifiers, not bearer tokens. There is nothing to refresh and nothing that expires:{ "merchant_id": "merch_example", "environment": "test", "grant_id": "grant_01HXX…", "granted_scopes": ["payments:write", "payments:read", "customers:write"], "token_type": "merchant_id" }grant_idis the handle for disconnecting the tenant later withPOST /v1/grants/{id}/revoke?environment=test(§5 of the Connect protocol). The identifier prefix does not select environment, and token exchange does not automatically create a Test merchant.
4. First on-behalf-of charge
Address the tenant with Mooov-Merchant and call the same payments
API a merchant would. Set MERCH in the signer to the returned
merchant_id. This example assumes a Test Stripe connection has been
configured for that tenant; confirm provider readiness with your contact.
Hosted checkout is the fastest path:
const paymentId = `pay_${crypto.randomUUID()}`;
const idempotencyKey = crypto.randomUUID(); // persist and reuse on retries
const res = await signedPost("/v1/payment_intents?environment=test", {
payment_id: paymentId,
amount: 4200, // minor units = £42.00
currency: "GBP",
flow: "redirect",
success_url: "https://your-platform.example/checkout/success",
cancel_url: "https://your-platform.example/checkout/cancel",
description: "Dues 2026",
}, "merch_example", idempotencyKey); // replace with the returned merchant_id
if (!res.ok) throw new Error(`Payment request failed: ${await res.text()}`);
const { provider } = await res.json();
// → send the tenant's customer to provider.hosted_url
Keep paymentId, the body, and idempotencyKey unchanged on retries.
For a Test Stripe checkout, pay with the test card
4242 4242 4242 4242 (any future expiry, any CVC); decline and 3DS
cards are on the sandbox page. A 403 here means the
grant is missing or revoked, or the action isn't in the granted
scopes; the error code table is in
§7 of the Connect protocol.
5. Verify webhooks
You register one platform-wide webhook URL during setup. Ordinary
payment events currently fan out to this destination for Live only,
subject to an active grant and the destination's enabled event types.
webhooks:configure is reserved and does not gate delivery. Connect
payloads currently have no environment or livemode field.
X-Mooov-Signature: t=<unix>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">
X-Mooov-Delivery: 42 (numeric delivery id, dedupe key)
Verify signatures in constant time before trusting the body. Do not wait
for a platform webhook from the Test charge above. Check
GET /v1/payment_intents/{id}/timeline?environment=test with your signed
request and merchant header instead. Validate your webhook receiver
locally with signed fixtures, then verify actual Live delivery during
your agreed Live certification. See
§6 of the Connect protocol and the
webhook event catalog.
6. Go live
- Run the go-live checklist, including the Connect-specific grant-revocation item.
- Coordinate Live readiness with
ops@movere.moneyfor your existing platform integration. No second platform key or webhook is needed. - Keep the canonical hosts:
https://api.mooov.moneyandhttps://connect.mooov.money/authorize. The API surface and platform credential remain identical; Live grants stay separate from Test grants. - Re-run consent with
mode=live, then use?environment=liveon API requests. With the tenant's authorization, make a low-value Live charge and verify its webhook before announcing. See Environments.
7. Watch your integration (platform portal)
Your team can use the Movere Platform Portal without calling the
API. Open https://connect.mooov.money/portal to switch between
platform workspaces and Test or Live, inspect the
merchant roster and payment ledger, review grants and activity, manage
team access, and monitor API-key and webhook health. Merchant-of-record
payments remain provider-neutral in this portal.
Access is invite-only. Ask your Movere contact to invite your technical lead by email; they'll receive a single-use link to set a password. An admin can also share the same one-time invite URL directly if email delivery is delayed. There is no self-signup, and portal logins are entirely separate from your API credentials. A portal account can never sign API requests.
Contact integrations@movere.money.