Skip to content

External credits & billing

Stripe isn't the only way to bill your customers. If you invoice through your own system — a bank transfer flow, another PSP, a marketplace, or manual sales — you can grant (and deduct) prepaid credits over the API. MicroAuth takes care of the ledger, the balance, and enforcement; your system stays the source of truth for payments.

Authentication: workspace API key

The credits endpoint is part of the management API, so it authenticates with a workspace API key (mak_...), not the tenant secret:

Authorization: Bearer mak_...

Create one in the MicroAuth app under Workspace settings → API keys. The key acts on behalf of the workspace and can manage every tenant in it; the full key is shown once at creation.

Don't confuse the key types

mas_ (tenant secret) is for the SDK API only. mak_ (workspace key) is for management endpoints like this one. See API keys at a glance.

The endpoint

POST https://api.microauth.com/v1/tenants/{tenantId}/customers/{customerId}/credits
  • tenantId — the tenant's UUID (visible in the app URL and via the API).
  • customerId — the customer's UUID. A "customer" is always a team (portal workspace), never an individual portal user — even a solo signup gets a single-member team behind the scenes, and the credit balance belongs to that team. Look customers up with GET /v1/tenants/{tenantId}/customers, or find the ID on the customer's detail page in the MicroAuth app.

Request body:

FieldTypeRequiredMeaning
amount_microintegeryesCredit amount in micro-USD (1,000,000 = $1.00). Positive to grant, negative to deduct. Must be non-zero.
descriptionstring (≤ 300)noFree-text shown in the ledger, e.g. "Invoice #2026-081"
external_refstring (≤ 120)noIdempotency key from your billing system — strongly recommended

Response:

json
{ "credit_balance_micro": 22500000 }

The new balance after the adjustment ($22.50 here).

Example: grant $10 for a paid invoice

bash
curl -X POST \
  "https://api.microauth.com/v1/tenants/$TENANT_ID/customers/$CUSTOMER_ID/credits" \
  -H "Authorization: Bearer mak_..." \
  -H "Content-Type: application/json" \
  -d '{
    "amount_micro": 10000000,
    "description": "Invoice #2026-081 paid via wire",
    "external_ref": "inv_2026_081"
  }'

The same in Python:

python
import requests

r = requests.post(
    f"https://api.microauth.com/v1/tenants/{TENANT_ID}/customers/{CUSTOMER_ID}/credits",
    headers={"Authorization": f"Bearer {WORKSPACE_KEY}"},
    json={
        "amount_micro": 10_000_000,          # $10.00
        "description": "Invoice #2026-081 paid via wire",
        "external_ref": "inv_2026_081",      # idempotency key
    },
    timeout=10,
)
r.raise_for_status()
print("new balance:", r.json()["credit_balance_micro"] / 1_000_000, "USD")

To deduct (a refund or chargeback), send a negative amount with its own reference, e.g. "amount_micro": -10000000, "external_ref": "refund_inv_2026_081".

Idempotency with external_ref

Billing systems retry. Webhooks fire twice. Networks fail after the request was applied but before you saw the response. external_ref makes all of that safe:

  • Each external_ref is unique per tenant. The first request with a given reference applies the adjustment and writes a ledger entry.
  • A replay with the same reference changes nothing — no duplicate ledger entry, no double credit — and returns 200 with the current balance.

So the safe pattern is simply: give every adjustment a stable reference derived from your system (invoice ID, payment intent ID, refund ID), and retry freely on timeouts.

One reference = one adjustment

Because replays are no-ops, don't reuse a reference for a different amount — it would be silently ignored. A refund needs its own reference, not the original invoice's.

Reading the ledger

Every adjustment — external, Stripe, subscription grant or usage charge — lands in the customer's credit ledger:

bash
curl "https://api.microauth.com/v1/tenants/$TENANT_ID/customers/$CUSTOMER_ID/ledger?limit=50&offset=0" \
  -H "Authorization: Bearer mak_..."
json
{
  "total": 3,
  "entries": [
    {
      "id": "5c1f...",
      "amount_micro": 10000000,
      "kind": "external_topup",
      "description": "Invoice #2026-081 paid via wire",
      "external_ref": "inv_2026_081",
      "created_at": "2026-08-03T18:04:11Z"
    }
  ]
}

External adjustments have kind: "external_topup" (for grants and deductions alike); Stripe top-ups, plan credit grants and other movements have their own kinds. The same ledger is visible in the MicroAuth app on the customer's detail page, and to the customer on their portal's Billing page.

How it plays with enforcement

The balance you adjust here is the same prepaid balance the SDK enforces:

  • SDKs pick up the new balance on their next snapshot refresh (~30s), so a customer who just paid is unblocked within moments.
  • Usage charges deduct from this balance automatically as usage is reported — you only need to put credits in (or claw them back).

See also

  • Custom integration — how usage gets charged against the balance.
  • The API reference — full schemas under the Customers tag, including customer listing, custom limits and suspension endpoints you may want in your billing automation.

MicroAuth is a product of Zyref, LLC.