Mooov Docs

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 Mooov 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, Mooov records a grant for the (platform, merchant) pair, and from then on you address that 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@mooov.money with:

Mooov provisions your integration against the sandbox first and you receive:

Sandbox and production are fully separate keys, grants, and webhook destinations; see Environments. You build and certify against the sandbox, then repeat the ceremony for production.

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>

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:

  1. You generate a signed state token and send the tenant's browser to the hosted authorize page:

    https://sandbox.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
    

    scope is 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.

  2. The tenant signs into Mooov (or creates an account), sees your display name and the requested scopes on a consent screen, and clicks Connect.

  3. Mooov records the grant and redirects to <redirect_uri>?code=<auth_code>&state=<your state>. The code is single-use and expires in 10 minutes.

  4. You verify state, then exchange the code with an HMAC-signed POST /v1/public/connect/token:

    {
      "grant_type":   "authorization_code",
      "code":         "<auth_code>",
      "redirect_uri": "<same redirect_uri as step 1>"
    }
    
  5. You store the merchant_id. The response is a durable identifier, not a bearer token. There is nothing to refresh and nothing that expires:

    {
      "merchant_id":    "merch_test_…",
      "grant_id":       "grant_01HXX…",
      "granted_scopes": ["payments:write", "payments:read", "customers:write"],
      "token_type":     "merchant_id"
    }
    

    Keep grant_id too; it's the handle for disconnecting the tenant later (§5 of the Connect protocol).

4. First on-behalf-of charge

Address the tenant with Mooov-Merchant and call the same payments API a merchant would. Hosted checkout is the fastest path:

const res = await signedPost("/v1/payment_intents", {
  payment_id:  `pay_${crypto.randomUUID()}`,   // your stable id
  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",
});                                             // Mooov-Merchant: merch_test_…
const { provider } = await res.json();
// → send the tenant's customer to provider.hosted_url

In the sandbox, 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 webhook URL per environment (part of the ceremony in step 1) and it receives signed events for all your connected tenants:

X-Mooov-Signature: t=<unix>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">
X-Mooov-Delivery:  42                           (numeric delivery id, dedupe key)

Verify the signature in constant time before trusting the body. After the test charge above you'll receive payment.succeeded within a couple of seconds. Verification code samples are in §6 of the Connect protocol; the full event list is in the webhook event catalog.

6. Go live

  1. Run the sandbox go-live checklist, including the Connect-specific grant-revocation item.
  2. Repeat the credential ceremony with ops@mooov.money for production. Production keys, grants, and webhook secrets are separate from the sandbox.
  3. Swap the base URLs: https://api.mooov.money and https://connect.mooov.money/authorize. The API surface is identical.
  4. Re-run the consent flow with a real tenant and make one low-value live charge before announcing. There is no test mode on production; see Environments.

7. Watch your integration (platform portal)

Your team can see your connected merchants and integration health without calling the API: the platform portal at https://connect.mooov.money/portal shows your merchant roster (grants, charge-readiness, payment volume), your webhook delivery posture (status, consecutive failures, last delivery), and your API key metadata (never the secrets).

Access is invite-only. Ask your Mooov contact to invite your technical lead by email; they'll receive a single-use link to set a password. There is no self-signup, and portal logins are entirely separate from your API credentials — a portal account can never sign API requests.

Questions: integrations@mooov.money.