Metrivo
Docs/Manual Payment API

Manual Payment API Reference

Record transactions from Stripe, Paddle, Gumroad, Lemon Squeezy, or any internal system using our simple REST endpoint.

Overview

If you aren't using our native Stripe, Razorpay, or Dodo integrations, the Manual Payment API lets you send transaction details directly from your backend. Metrivo takes the payload parameters, matches it with tracked browser sessions, and builds your revenue attribution dashboard.

Retrieve your workspace API token in the Metrivo dashboard under Settings → API Keys. Secure the token in your environment variables; never share it or use it on the frontend.

Before starting checkout, call window.Metrivo.getAttributionMetadata() in the browser and send that object to your backend. Copy metrivo_visitor_id, metrivo_session_id, and UTM/referrer/click ID fields into the Manual Payment API payload when the payment succeeds.

API Endpoints

POST/api/payments/manual

Record a payment to attribute it back to user visits.

Request Headers

Content-Type: application/json
Authorization: Bearer <API_KEY>

Request Body Schema

website_idUUID stringYesThe ID of the website. Copy it from your Website Settings.
amountpositive floatYesThe positive cash value of the sale (e.g. 49.00).
currency3-char stringNoISO currency code (e.g., USD, EUR). Defaults to USD.
provider_payment_idstringYesUniquely identifies this purchase inside your checkout platform.
providerstringNoPayment processor keyword (e.g., paddle, lemon_squeezy). Defaults to manual.
statusstringNoDefaults to paid.
customer_emailemail stringNoMatches email hashes in case visitor metadata is missing.
paid_atISO date stringNoDatetime when payment occurred. Defaults to now.
metrivo_visitor_idUUID stringNoClient-side visitor ID from window.Metrivo.getAttributionMetadata().
metrivo_session_idUUID stringNoClient-side session ID from window.Metrivo.getAttributionMetadata().
landing_urlURL stringNoLanding or checkout page URL from the metadata helper.
referrerURL stringNoBrowser referrer from the metadata helper.
utm_sourcestringNoUTM source from the metadata helper.
utm_mediumstringNoUTM medium from the metadata helper.
utm_campaignstringNoUTM campaign from the metadata helper.
utm_termstringNoUTM term from the metadata helper.
utm_contentstringNoUTM content from the metadata helper.
gclidstringNoGoogle Ads click ID from the metadata helper.
fbclidstringNoMeta/Facebook click ID from the metadata helper.
msclkidstringNoMicrosoft Ads click ID from the metadata helper.
ttclidstringNoTikTok click ID from the metadata helper.
metadataJSON objectNoArbitrary JSON metadata dictionary. Defaults to {}.

Client Metadata Helper

const metrivo = window.Metrivo.getAttributionMetadata()

await fetch("/api/create-checkout", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    plan: "growth",
    metrivo
  })
})

cURL Snippet Example

curl -X POST https://metrivo.co/api/payments/manual \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <API_KEY>" \
  -d '{
    "website_id": "<WEBSITE_ID>",
    "amount": 49.00,
    "currency": "USD",
    "provider_payment_id": "<PAYMENT_ID>",
    "metrivo_visitor_id": "a1b2c3d4-7e8f-4a9b-8c7d-123456789abc",
    "metrivo_session_id": "b7f2db6a-7d74-45db-9796-3ddc9f6f2c74",
    "landing_url": "https://example.com/pricing?utm_source=google",
    "referrer": "https://google.com",
    "utm_source": "google",
    "utm_medium": "cpc",
    "utm_campaign": "launch",
    "customer_email": "user@example.com",
    "provider": "paddle",
    "status": "paid",
    "paid_at": "2026-05-19T23:38:00.000Z",
    "metadata": {
      "plan": "growth"
    }
  }'

Response Body (200 OK)

{
  "success": true,
  "verification": {
    "requestAccepted": true,
    "paymentRowCreated": true,
    "attributionMatched": true,
    "attributionConfidence": "high",
    "missingVisitorMetadata": false,
    "missingSessionMetadata": false
  },
  "payment": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "website_id": "6f7c9f52-27f2-4f58-bc27-fc45f0c9c001",
    "amount": 49,
    "currency": "USD",
    "provider_payment_id": "ch_3M4Y8kBzG9sP6i4w5o9e8t7q",
    "attributed_source": "google",
    "attributed_medium": "organic",
    "attribution_confidence": "high"
  }
}
POST/api/identify

Connect an anonymous visitor ID to an email address or user account identifier. Call this backend endpoint or use the client browser API.

Client JS API Example

window.Metrivo.identify("user@example.com", {
  plan: "growth",
  company: "Acme Inc"
})

cURL Server API Example

curl -X POST https://metrivo.co/api/identify \
  -H "Content-Type: application/json" \
  -d '{
    "publicKey": "<PUBLIC_KEY>",
    "visitorId": "a1b2c3d4-7e8f-4a9b-8c7d-123456789abc",
    "email": "user@example.com",
    "properties": {
      "plan": "growth",
      "company": "Acme Inc"
    }
  }'

Best Practices

Attach tracking IDs on Checkout creation

Pass the browser-level Metrivo session and visitor fields to your server when checkout begins. Link them as custom metadata inside your checkout creation calls to enable a high-confidence match when the webhook carries those fields back.

Enforce payment provider_payment_id uniqueness

Metrivo tracks uniqueness using the composite columns of website_id, provider, and provider_payment_id to prevent duplicate transaction entries. Ensure you populate provider_payment_id correctly.

Secure your workspace secrets

Ensure your Metrivo API key is stored safely on secure production backends. Do not expose it in frontend JS files, static scripts, or GitHub repositories.

HTTP Status Error Codes

401Missing or invalid Authorization header. Check your Bearer token.
400Invalid payload parameters. Ensure website_id, amount, and provider_payment_id satisfy formatting constraints.
403Scope mismatch. Your API key lacks payments:write access or is not permitted to write to the requested website.
500Internal database failure. Typically caused by duplicate provider_payment_id entries.

Ready to attribute conversions?

Install the tracking snippet and trigger your first payment webhook to populate your dashboards.