diff --git a/api-reference/accounts/auto-recharge-get.mdx b/api-reference/accounts/auto-recharge-get.mdx new file mode 100644 index 00000000..2e7e2773 --- /dev/null +++ b/api-reference/accounts/auto-recharge-get.mdx @@ -0,0 +1,4 @@ +--- +title: "Get Auto Top-Up Setting" +openapi: "/api-reference/openapi/accounts.json GET /api/accounts/{id}/auto-recharge" +--- diff --git a/api-reference/accounts/auto-recharge-update.mdx b/api-reference/accounts/auto-recharge-update.mdx new file mode 100644 index 00000000..15ff5258 --- /dev/null +++ b/api-reference/accounts/auto-recharge-update.mdx @@ -0,0 +1,4 @@ +--- +title: "Update Auto Top-Up Setting" +openapi: "/api-reference/openapi/accounts.json PATCH /api/accounts/{id}/auto-recharge" +--- diff --git a/api-reference/openapi/accounts.json b/api-reference/openapi/accounts.json index 8b7858d0..b8c50f33 100644 --- a/api-reference/openapi/accounts.json +++ b/api-reference/openapi/accounts.json @@ -1000,6 +1000,167 @@ } } }, + "/api/accounts/{id}/auto-recharge": { + "get": { + "description": "Retrieve whether automatic top-up is enabled for the account.", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The unique identifier (UUID) of the account. Must be the authenticated account or another accessible via organization membership.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "security": [ + { + "apiKeyAuth": [] + }, + { + "bearerAuth": [] + } + ], + "responses": { + "200": { + "description": "Auto top-up setting returned successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountAutoRechargeResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing authentication", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountAutoRechargeErrorResponse" + }, + "example": { + "error": "Unauthorized" + } + } + } + }, + "403": { + "description": "Forbidden - account not accessible to the authenticated account", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountAutoRechargeErrorResponse" + } + } + } + }, + "404": { + "description": "Account not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountAutoRechargeErrorResponse" + } + } + } + } + } + }, + "patch": { + "description": "Enable or disable automatic top-up for the account.", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The unique identifier (UUID) of the account. Must be the authenticated account or another accessible via organization membership.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "security": [ + { + "apiKeyAuth": [] + }, + { + "bearerAuth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountAutoRechargeUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Auto top-up setting returned successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountAutoRechargeResponse" + } + } + } + }, + "400": { + "description": "Invalid request body - `enabled` must be a boolean", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountAutoRechargeErrorResponse" + }, + "example": { + "error": "enabled must be a boolean" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing authentication", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountAutoRechargeErrorResponse" + }, + "example": { + "error": "Unauthorized" + } + } + } + }, + "403": { + "description": "Forbidden - account not accessible to the authenticated account", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountAutoRechargeErrorResponse" + } + } + } + }, + "404": { + "description": "Account not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountAutoRechargeErrorResponse" + } + } + } + } + } + } + }, "/api/credits/sessions": { "post": { "description": "Top up credits on the authenticated account.\n\n**One credit equals one US cent (\\$0.01).** The customer is charged `credits` plus a Stripe processing fee (US card pricing: 2.9% + \\$0.30) \u2014 e.g. `credits: 10000` charges \\$103.30 total (\\$100.00 credits + \\$3.30 fee).\n\n**Two outcomes, distinguished by response shape:**\n\n- **Auto-charged** \u2014 if the account has a card on file (from a prior subscription or top-up), the card is charged immediately and the response is `{ paymentIntentId, creditsPurchased, totalCents }`. Credits land in the account's balance asynchronously via Stripe webhook (typically within seconds). No human interaction required.\n\n- **Checkout required** \u2014 if no card is on file, or the saved card requires 3-D Secure authentication, the response is `{ id, url }` with a hosted Stripe Checkout URL. Redirect to that URL; credits land on successful payment.\n\nClients should discriminate on the presence of `url` (Checkout) vs `paymentIntentId` (auto-charged). Cards entered through the Checkout fallback are saved for future top-ups, so a customer's second top-up typically auto-charges.", @@ -4277,6 +4438,51 @@ } } }, + "AccountAutoRechargeResponse": { + "type": "object", + "required": [ + "account_id", + "enabled" + ], + "properties": { + "account_id": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the account this setting belongs to.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "enabled": { + "type": "boolean", + "description": "Whether automatic top-up is enabled. `false` means the account has opted out and only explicit checkout top-ups can charge it.", + "example": true + } + } + }, + "AccountAutoRechargeUpdateRequest": { + "type": "object", + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "type": "boolean", + "description": "Set `false` to opt out of automatic top-up, `true` to opt back in." + } + } + }, + "AccountAutoRechargeErrorResponse": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "description": "Human-readable error message.", + "example": "Unauthorized" + } + } + }, "CreateCreditsSessionRequest": { "type": "object", "required": [ diff --git a/credits.mdx b/credits.mdx index ab68b776..a928d1cd 100644 --- a/credits.mdx +++ b/credits.mdx @@ -115,7 +115,7 @@ Response shape: ## Automatic top-up -Every billed API request runs a credit gate before it executes. If `remaining_credits` doesn't cover the request's cost **and** the account has a saved Stripe card, Recoup silently charges **$5 (500 credits)** off-session and lets the request proceed. Most accounts with a working card never see an "insufficient credits" failure — the top-up is invisible. +Every billed API request runs a credit gate before it executes. If `remaining_credits` doesn't cover the request's cost **and** the account has a saved card **and** the account hasn't opted out (see [Opting out](#opting-out) below), Recoup silently charges **$5 (500 credits)** off-session and lets the request proceed. Most accounts with a working card never see an "insufficient credits" failure — the top-up is invisible. The decision tree: @@ -125,10 +125,32 @@ The decision tree: ### When auto top-up doesn't trigger +- The account has opted out of automatic top-up → 402 with `checkoutUrl`, no `declineReason`. The saved card is never charged off-session while opted out. - The account has no saved Stripe card → 402 with `checkoutUrl`, no `declineReason`. - Stripe declines the saved card (insufficient funds, expired, fraud, 3-D Secure required, etc.) → 402 with `checkoutUrl` + `declineReason`. - A single request needs more than 500 credits (rare — only `POST /api/research/deep` at 25 and oversized `extract` calls come close) → request fails even though the top-up succeeded. +### Opting out + +Automatic top-up is on by default and can be disabled per account: + +```bash +curl -sS -X PATCH https://api.recoupable.dev/api/accounts/$ACCOUNT_ID/auto-recharge \ + -H "x-api-key: $RECOUP_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{"enabled": false}' +``` + +```json +{ + "account_id": "acc_…", + "enabled": false +} +``` + +While opted out, no off-session charge is ever attempted: billed requests that exceed the remaining balance return **HTTP 402** with a `checkoutUrl` (see below), and topping up stays an explicit action. Opting out does **not** remove the saved card — manual top-ups through checkout keep working, and re-enabling later (`{"enabled": true}`) requires no card re-entry. Read the current setting with `GET /api/accounts/$ACCOUNT_ID/auto-recharge`. Full schema at [Get Auto Top-Up Setting](/api-reference/accounts/auto-recharge-get) and [Update Auto Top-Up Setting](/api-reference/accounts/auto-recharge-update). + + ### Tuning The auto top-up amount is currently a constant at **$5 / 500 credits**. Per-account thresholds are not yet exposed — reach out to support if you need a different default. @@ -179,7 +201,7 @@ Current as of this revision of the page. The authoritative source is the per-end | [`POST /api/chat`](/api-reference/chat/workflow) (streaming) | ≥1 credit per turn — variable based on model token usage | | [`GET /api/research/*`](/api-reference/research/search) (artist & non-artist research) | 5 credits per call | | [`POST /api/research/people`](/api-reference/research/people) | 5 credits per call | -| [`POST /api/research/web`](/api-reference/research/web) | 5 credits per call | +| [`POST /api/research/web`](/api-reference/research/web) | 1 credit per call | | [`POST /api/research/extract`](/api-reference/research/extract) | 5 credits × number of URLs | | [`POST /api/research/enrich`](/api-reference/research/enrich) | 5 / 10 / 25 credits (base / core / ultra processor) | | [`POST /api/research/deep`](/api-reference/research/deep) | 25 credits per call | diff --git a/docs.json b/docs.json index dc905ccf..cb0fc0a8 100644 --- a/docs.json +++ b/docs.json @@ -336,7 +336,9 @@ "api-reference/accounts/subscription-get", "api-reference/credits/sessions-create", "api-reference/accounts/credits-get", - "api-reference/accounts/payment-method-get" + "api-reference/accounts/payment-method-get", + "api-reference/accounts/auto-recharge-get", + "api-reference/accounts/auto-recharge-update" ] }, {