movere 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 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:

Movere provisions a platform credential and you receive:

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:

  1. You generate a signed state token 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=test
    

    mode=test creates a Test grant; use mode=live for Live. Omission defaults to Live. URL-encode parameter values when building the URL.

    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 Movere (or creates an account), sees your display name and the requested scopes on a consent screen, and clicks Connect.

  3. 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.

  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. Store merchant_id, grant_id, and environment. 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_id is the handle for disconnecting the tenant later with POST /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

  1. Run the go-live checklist, including the Connect-specific grant-revocation item.
  2. Coordinate Live readiness with ops@movere.money for your existing platform integration. No second platform key or webhook is needed.
  3. Keep the canonical hosts: https://api.mooov.money and https://connect.mooov.money/authorize. The API surface and platform credential remain identical; Live grants stay separate from Test grants.
  4. Re-run consent with mode=live, then use ?environment=live on 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.