Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.paywalls.ai/llms.txt

Use this file to discover all available pages before exploring further.

Learn how to grant or top up user balances programmatically using the Deposit API. This is useful for signup bonuses, subscription renewals, refunds/goodwill, migrations, or promotions.
This guide applies to Default mode (you control payments). In Shared mode, users fund a hosted, cross‑app wallet and you don’t deposit credits directly. See Shared Mode.
1

Prerequisites

  • Default mode enabled and your Paywalls API key configured.
  • A stable, pseudonymous user id selected. See User Identity.
2

Call the Deposit API

Use POST /v1/user/balance/deposit/post. Amount is a string in your configured currency (e.g., “10”).
curl -X POST https://api.paywalls.ai/v1/user/balance/deposit \
-H "Authorization: Bearer $PAYWALLS_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $UNIQUE_EVENT_ID" \
-d '{
	"user": "user_123",
	"amount": "10",
	"metadata": {
		"reason": "signup_bonus",
		"source": "marketing_campaign_2025_09"
	}
}'
3

Verify and display balances

  • The deposit appears in the Ledger immediately.
  • Optionally fetch the updated balance for display using GET /user/balance.
Include Idempotency-Key so repeated webhooks or retries do not create duplicate credits.

Common scenarios

1. Signup bonus on registration

Grant a one‑time credit when a new account is created.
  • Amount: small trial amount (e.g., “1.00”)
  • Metadata: {"reason":"signup_bonus","signup_event":"evt_signup_123"}
// Example: in your user-created handler
await fetch("https://api.paywalls.ai/v1/user/balance/deposit", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.PAYWALLS_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": `signup:${userId}`, // stable for this logical event
  },
  body: JSON.stringify({
    user: userId,
    amount: "1.00",
    metadata: { reason: "signup_bonus" },
  }),
});

2. Subscription renewal credits

Credit users monthly after your PSP confirms payment (e.g., Stripe invoice.payment_succeeded).
  • Amount: your plan’s included usage value (e.g., “10.00”)
  • Metadata: include invoice id, plan, period_start/end for reconciliation
// Example: in your Stripe webhook handler (invoice.payment_succeeded)
const {
  id: invoiceId,
  payment_intent: pi,
  customer,
  lines,
} = event.data.object;
await fetch("https://api.paywalls.ai/v1/user/balance/deposit", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.PAYWALLS_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": invoiceId, // prevents duplicates on retries
  },
  body: JSON.stringify({
    user: mapStripeCustomerToUserId(customer),
    amount: planIncludedCreditsAmount(lines), // e.g., "10.00"
    metadata: {
      reason: "subscription_included_credits",
      invoice_id: invoiceId,
      payment_intent: pi,
    },
  }),
});
See Connect Stripe for Default mode setup.

No‑code (Zapier, n8n)

You can call the Deposit API from no‑code tools to credit balances without custom code.
Prefer injecting a stable user from your CRM/DB. For no‑code patterns, see No-code: Zapier, n8n, and other flows.

Best practices

  • Idempotency first: reuse the same Idempotency-Key on retries/webhook replays.
  • Pseudonymous identity: avoid PII in user ids. See User Identity.
  • Don’t expose keys: keep PAYWALLS_API_KEY server/edge only.
  • Reconciliation: store invoice/payment ids in metadata. Use the Ledger and Analytics & Reporting.
  • Testing: use Stripe test mode in Default mode staging. See Test keys & Environments.

Deposit API

Reference for POST /user/balance/deposit.

User balance (GET)

Fetch and display a user’s current balance.

Pricing & Metering

How charges are computed and written to the ledger.