---
title: "Invoke Billing Topup"
method: POST
path: "/v1/op/billing.topup"
tags: ["kernel"]
---

# Invoke Billing Topup

`POST /v1/op/billing.topup`

Off-session card charge → credits. Idempotency is at the STRIPE level: the
client's Idempotency-Key is threaded into charge_for_credits (Stripe dedups the
charge, the PaymentIntent id dedups the grant), matching the legacy /billing/topup
exactly. On 3DS/SCA the op raises a 402 carrying the PaymentIntent client_secret,
which we surface at the TOP LEVEL of the problem body — `problem.client_secret` —
because that's what the topup page reads to drive confirmCardPayment.

## Headers

- `Idempotency-Key` string, nullable
- `x-api-key` string, nullable

## Request body

- object, nullable

## Response `201`

Successful Response

- unknown

## Other responses

- `401` — Unauthorized
- `403` — Forbidden
- `404` — Not Found
- `422` — Validation Error
- `500` — Internal Server Error

---

[API](https://skmtc.dev/geopera/apis/geopera-data-platform.md) · [All operations](https://skmtc.dev/geopera/apis/geopera-data-platform/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/geopera/geopera-data-platform/revisions/cb0130b2a40a/schema)
