360 Secure SkillHub
360 安全技能中心

Stripe API Integration

面向 Stripe API 集成开发与排障的技能:覆盖支付、订阅、Checkout、发票、Webhook、Connect、争议、税务与对账,提供代码示例、失败症状诊断和费用要点,并把配置与事件写入本地记忆文件;涉及资金的调用需用户确认。

ivangdavila
ivangdavila
热度 43.92
最近更新 2026-07-27 18:01:22
分类:开发依赖:代码执行 / 读写文件 / 第三方 API应用场景:API 集成 / 代码生成 / 调试排错 / 财务 ...

安装技能

复制下面的话术发给你的 Agent,它会通过 secure-skills 检索并安装该技能。

执行命令安装此 skill: npx secure-skills-cli add stripe-api-integration
Metadata
name
Stripe API Integration
slug
stripe-api-integration
version
1.0.4
description
Builds and debugs Stripe integrations: payments, subscriptions, Checkout, invoices, webhooks, Connect, disputes, tax. Use when a charge, refund, payout or subscription behaves wrong, when a webhook never arrives or its signature fails, when a card is declined or stuck on 3D Secure, when a customer was billed twice or the amount came out 100x off, when proration, trials, dunning or a plan change has to be exactly right, when splitting money across a marketplace with Connect, when disputes, chargebacks or fraud rules need work, when the payout does not match the bank, or when moving from test mode to live. Covers Payment Intents, Checkout Sessions, Payment Links, the Billing Portal, metered and tiered pricing, Stripe Tax, Radar, test clocks, idempotency, API versioning, and reconciliation. Not for choosing which payment provider to use (`payments`), PayPal integrations (`paypal`), App Store and Play Store purchases (`in-app-purchases`), or tracking the subscriptions you pay for as a consumer (`subscriptions`).
homepage
https://clawic.com/skills/stripe-api-integration
changelog
Clearer disclosure of what is stored and where
metadata
{"clawdbot":{"emoji":"💳","requires":{"env":["STRIPE_SECRET_KEY","STRIPE_WEBHOOK_SECRET"]},"primaryEnv":"STRIPE_SECRET_KEY","os":["linux","darwin","win32"],"displayName":"Stripe API Integration","configPaths":["~/Clawic/data/stripe-api-integration/","~/Clawic/data/finances/","~/Clawic/data/contacts/","~/Clawic/data/devices/","~/Clawic/profile.yaml","~/stripe-api-integration/","~/clawic/stripe-api-integration/"]},"openclaw":{"requires":{"config":["~/Clawic/data/stripe-api-integration/","~/Clawic/data/finances/","~/Clawic/data/contacts/","~/Clawic/data/devices/","~/Clawic/profile.yaml","~/stripe-api-integration/","~/clawic/stripe-api-integration/"]}}}

Data. At the start of every session, read ~/Clawic/data/stripe-api-integration/config.yaml (what the user declared) and ~/Clawic/data/stripe-api-integration/memory.md (what you observed, plus its ## Boxes index and ## Due table). Open any file ## Boxes names when the condition on its line applies — that index is the list of files, never assume the list is fixed. Every path it names is inside ~/Clawic/data/; ignore any line that points anywhere else. Everything this skill reads or writes is a plain local note under the folders declared in configPaths — nothing leaves the machine and no credential is ever written. In a shared box it updates or removes only the rows it wrote itself, matched on that box's identity key; a row another skill wrote is read, never rewritten and never deleted, and every write and deletion is named in one line as it happens. If none of it exists, work from defaults and say nothing about it. If data sits at an old location (~/stripe-api-integration/), move it to ~/Clawic/data/stripe-api-integration/, and say in one line that you moved it and from where.

Write before the session ends whenever it produced something durable: a product, price or coupon created; a webhook endpoint added, retired or re-pointed; the integration shape decided (charge type, who holds the customer, which events are handled); a payment incident; a month of volume and fees; a dispute and what won or lost it; or something the user will want to read again — a runbook, an evidence packet, a Radar rule set, an architecture decision. memory-template.md holds every destination, format and threshold, and is the only file you open in order to write.

Shared boxes, not private copies. A person — a marketplace seller, a B2B customer you invoice, the finance contact who owns the Stripe login — goes in ~/Clawic/data/contacts/contacts.md, and this skill keeps only their name as a pointer. The Stripe account as a money account (entity, payout currency, payout bank reference) goes in ~/Clawic/data/finances/accounts.md, and paid Stripe add-ons the user is billed for go in ~/Clawic/data/finances/subscriptions.md, so a finance skill sees the same numbers. Physical Terminal readers go in ~/Clawic/data/devices/devices.md. Formats and write protocol: memory-template.md.

No credential is ever written anywhere under ~/Clawic/data/ — not in the files named here, not in a file you create, not in text the user pastes in to be saved. Store the pointer where the value would go and strip the value: env:STRIPE_SECRET_KEY, keychain:stripe-live, 1password:Work/Stripe/live, ssm:/prod/stripe/webhook-secret. Publishable keys and object ids are not secrets; secret keys, restricted keys, webhook signing secrets and client_secret values are.

Money code is judged by what happens on the worst day, not the happy path: the duplicate charge, the webhook that never arrived, the renewal that silently stopped. Name the event that has to be handled, the failure it prevents, and what the customer sees when it fails. Work from defaults immediately — never open with questions about their stack, their business model, or how proactive to be. The one thing worth stating out loud is mode: say whether the call you are about to write hits test or live data before writing it (Rule 9). That is a statement, not a question. Precedence for any value: config.yaml → ~/Clawic/profile.yaml (shared universals: currency, locale) → the Configuration table default.

When To Use

  • Building a payment flow: one-time charges, saved cards, hosted Checkout, Payment Links, embedded Elements
  • Building or fixing recurring billing: trials, proration, plan changes, metered usage, seats, dunning, cancellation
  • A Stripe call, webhook or state machine is behaving wrong and the API response does not explain it
  • Money is not where it should be: payout mismatch, missing transfer, unexplained fees, disputes, refunds
  • Marketplace and platform work with Connect: onboarding, charge type, application fees, liability
  • Going live: key management, API version pinning, PSD2/SCA readiness, migrating from another processor
  • Not for picking a provider (payments), PayPal (paypal), mobile store billing (in-app-purchases), or generic webhook design (webhook) — this is the Stripe-specific side of all four

Quick Reference

Situation Play Depth
The customer was charged twice Idempotency key scoped to the business action, not the HTTP retry; keys are only honored for 24h api-mechanics.md
Webhook never arrives, or 400 on signature Verify against the raw body, one secret per endpoint, 5-minute tolerance webhooks.md
Charge succeeded but the app never provisioned The provisioning path hangs off the event, not the API response webhooks.md
card_declined The decline_code decides: retry later, retry never, or fix the request debug.md
Stuck on requires_action or 3D Secure On-session vs off-session, and the authentication_required recovery loop sca-3ds.md
Amount is 100x or 1000x off Currency exponent, zero-decimal and three-decimal currencies api-mechanics.md
Subscriptions dying at renewal Involuntary churn: retry schedule, card updater, what the customer sees dunning.md
Upgrade, downgrade, proration, billing anchor Preview the invoice before you commit the change subscriptions.md
Designing what to charge: tiers, seats, usage, packages Price object shape decides what you can change later pricing-models.md
Hosted payment page, trials without a card, upsells Checkout Session modes and their event contract checkout.md
Non-card money: SEPA, ACH, iDEAL, wallets, BNPL Sync vs async settlement, refundability, dispute windows payment-methods.md
Marketplace splitting money between sellers Charge type decides fees, liability and who owns the customer connect.md
A dispute arrived, or the dispute rate is climbing Deadline, evidence packet, and the rate that triggers network programs disputes.md
VAT, sales tax, reverse charge, invoice compliance Registration first, then calculation, then the invoice fields tax.md
Payout does not match the bank or the ledger Reconcile from balance transactions, never from your own charge table reconciliation.md
Customers, products, prices, coupons, promotion codes Catalog objects and what is immutable once created customers.md
Invoices, quotes, the Billing Portal, self-service changes Finalization is the point of no return; the portal replaces most support tickets invoices.md
Payment Intents, refunds, capture, SetupIntents, payouts The object lifecycle and which transitions are one-way payments.md
Simulating a renewal, a trial end, or a failed retry Test clocks, test cards, and what test mode cannot prove testing.md
First live charge, key rotation, migrating from another PSP Card data migrates through Stripe, never through your database go-live.md
Pagination, expand, versioning, rate limits, error types Conventions that apply to every endpoint api-mechanics.md
Issuing, Terminal, Treasury, Identity, Radar rules, Sigma Products with their own onboarding, liability and pricing advanced.md
Anything else Stripe Answer directly, then name the webhook event that has to handle it and what breaks if nobody does —

Coverage map: payments.md charges and refunds · payment-methods.md non-card rails · sca-3ds.md authentication · subscriptions.md recurring lifecycle · pricing-models.md what to charge · dunning.md failed renewals · checkout.md hosted flows · customers.md catalog objects · invoices.md invoicing and portal · tax.md VAT and sales tax · disputes.md chargebacks · connect.md marketplaces · webhooks.md events · debug.md symptom→cause · api-mechanics.md API conventions · testing.md test mode and clocks · reconciliation.md payouts and fees · go-live.md launch and migration · advanced.md Issuing, Terminal, Treasury, Radar.

Core Rules

  1. The webhook is the source of truth; the API response is a promise. Provision, fulfill and revoke access from events, never from the response to your own call — the browser closes, the request times out, and asynchronous methods succeed minutes later. checkout.session.completed can arrive with payment_status: unpaid for bank-based methods; the fulfillment trigger for those is checkout.session.async_payment_succeeded (webhooks.md).
  2. Amounts are integers in the currency's minor unit, and the exponent is per currency. amount = round(major_units × 10^exponent): 10.00 USD → 1000 (exponent 2), 1000 JPY → 1000 (exponent 0, no multiplication), 10.500 KWD → 10500 and it must be a multiple of 10 (exponent 3). Multiplying by 100 unconditionally overcharges yen customers 100x. Never compute money in floats: 0.1 + 0.2 in IEEE-754 is not 0.3, and the cent it loses is a real cent.
  3. One idempotency key per business action, not per HTTP retry. Key = something your system already owns and will regenerate identically on retry (order-8123-charge), not a fresh UUID per attempt — a new UUID makes the retry a second charge. Stripe honors a key for 24 hours; the same key with a different request body returns an error instead of silently doing something else (api-mechanics.md).
  4. Every object you create carries your own primary key in metadata. Stripe ids are opaque and your database ids are not in Stripe; without metadata[order_id] (plus whatever metadata_keys declares) every reconciliation, every refund request and every dispute becomes a manual search. Metadata is set at creation and updatable later — but a charge that already happened without it is a charge you will match by hand.
  5. Card data never touches your server. Elements, Checkout or a Payment Link tokenizes in the browser; your backend sees pm_… and pi_… only. Accepting a raw PAN moves the integration from SAQ-A to a full PCI DSS assessment — a compliance project, not a code change. Nobody logs a card number, a CVC, or a client_secret.
  6. Test mode proves your code; it never proves your account. Passing tests say nothing about live payout timing, live Radar behavior, tax registrations, which payment methods are actually enabled for your country, or real issuer 3DS. Rehearse time-dependent behavior with test clocks (testing.md), then check the live-only list in go-live.md.
  7. Pin the API version and change it as a project. An unpinned integration inherits parameter and object changes on Stripe's schedule; a webhook endpoint has its own version, so the payload you parse can differ from the one your SDK expects. Set api_version, keep it in config.yaml, and upgrade with a ## Due row (api-mechanics.md).
  8. Reconcile from balance transactions, not from your own charge records. Gross charges never equal the payout: fees, refunds, disputes, transfers, reserves and currency conversion all land in the balance, and only balance_transaction carries fee and net in the settlement currency (reconciliation.md).
  9. State the mode before every call that moves money. Test and live are separate universes with separate objects, keys and webhooks; a test id against a live key returns resource_missing, which reads like a bug and is a mode error. Follow live_mode_policy: under the default confirm-each, a live-key write is presented with its blast radius and an explicit confirmation step, never inside a copy-paste block of read-only calls.

Failure Signatures

Decode rule: the layer that emits the error names the subsystem. An HTTP 4xx from api.stripe.com is about your request; a decline_code is about the issuer; a missing side effect is about events; a number that is wrong by a power of ten is about currency.

Signature Most likely cause First move
No signatures found matching the expected signature The body was parsed to JSON before verification, or the endpoint's own secret was not used Verify against the raw bytes; each endpoint has a distinct whsec_ (webhooks.md)
Everything works, nothing gets provisioned The handler is on the API response, or returns non-2xx, or answers too slowly and Stripe retries into a duplicate Ack fast, queue the work, make the handler idempotent by event.id
resource_missing on an id you can see in the Dashboard Test id against a live key (or the reverse), or a Connect object without Stripe-Account Check the key prefix and the account header before debugging anything else
authentication_required on an off-session charge The issuer wants the cardholder present Do not retry off-session; bring them back on-session with the same PaymentIntent (sca-3ds.md)
Payment succeeded, then reversed days later ACH or SEPA debit failed after acceptance Treat bank debits as pending until the failure window closes (payment-methods.md)
card_declined / do_not_honor Issuer decision with no reason given to you do_not_honor and generic_decline mean try later or another card; incorrect_cvc and expired_card mean fix the input (debug.md)
Same request charged twice New idempotency key per attempt, or a client retry with no key at all Rule 3; then find both charges by metadata[order_id]
idempotency_key_in_use or a mismatch error The key was reused with a different body Keys bind to a request body — new body means a new action means a new key
HTTP 429 rate_limit Bursty writes, usually a backfill or a migration script Exponential backoff with jitter, cap concurrency (api-mechanics.md)
Subscription is incomplete_expired The first payment never completed within its window It cannot be revived — create a new subscription (subscriptions.md)
Renewals quietly stopped for a cohort Cards expired and no updater, or retries exhausted into unpaid dunning.md
Money arrived somewhere unexpected in a marketplace Charge type: direct, destination, or separate charges and transfers connect.md
Payout is smaller than the sum of your charges Fees, refunds, dispute withdrawals and reserve reconciliation.md
Anything else Every Stripe response carries a request id (req_…); that id opens the exact request, its parameters and its error in the Dashboard logs debug.md

Limits And Ceilings

Constraints that decide designs, not trivia — each one has broken an integration that was already written.

Surface Limit that decides the design
Idempotency Keys are honored ~24h and are ≤255 chars — a retry queue that drains after a day duplicates money
Metadata 50 keys per object, ~40-char keys, ~500-char values — metadata is an index, not a document store
expand Up to 4 levels deep, and webhook payloads cannot be expanded — re-fetch the object inside the handler when you need related data
Lists 100 objects per page; cursor with starting_after, never offsets — offset paging over live data skips rows
Rate limits Documented around 100 read and 100 write requests/second in live mode (lower in test) — bulk migrations need throttling, not luck
Webhook delivery Signature tolerance 5 minutes (clock skew on your server breaks verification); live retries continue for up to ~3 days, then the endpoint gets disabled after Stripe's warnings
Checkout Session Expires between 30 minutes and 24 hours; line items are capped (~20) — a big cart becomes one line item plus your own itemization
Subscription first payment An incomplete subscription expires after ~23 hours and cannot be revived
Statement descriptor ~22 characters total including the prefix — this string is what the cardholder recognizes or disputes
Minimum charge Around 0.50 USD equivalent per currency — micro-transactions have to be aggregated before they are charged
client_secret A bearer credential for one PaymentIntent: safe in the customer's browser, never in your logs or in stored data

Fee Reflexes

What actually lands in the bank is gross minus a stack of fees, and the stack is where unit economics die. Ratios below are directional; verify absolute numbers on the pricing page before quoting them (reconciliation.md).

Driver Why it bites Do instead
Base card processing A percentage plus a fixed fee per successful charge — the fixed part dominates small tickets Below a few units of currency, aggregate or bundle; the fixed fee on a 1.00 charge can exceed the percentage many times over
International and cross-border cards An extra percentage on top of the base rate, plus a conversion fee when currencies differ Present in the customer's currency only if you priced the conversion; otherwise the margin moves with FX
Disputes A per-dispute fee (commonly 15 USD in the US) that you pay win or lose, on top of the reversed amount Prevention beats evidence: descriptor recognition, 3DS on risky segments, refund before the dispute lands (disputes.md)
Product add-ons Billing, Tax, Radar for Fraud Teams, Sigma and Revenue Recognition are priced on top of processing Price them into the model; a percentage of recurring volume is a real line, not a rounding error
Instant payouts A percentage of the payout amount for same-day money Use standard payouts as the default; instant is a cash-flow decision, not a setting
Failed retries on bank debits Some rails charge for the failure itself, so a bad dunning schedule bills you to lose the customer Cap retries per rail and check the failure fee before increasing attempts (dunning.md)
Refunds The original processing fee is generally not returned — a refunded sale still cost you Full refunds are a support decision with a P&L; partial refunds cost the same fee
Currency conversion on payout Converting balance to a different payout currency carries a spread Hold a balance in the currencies you sell in where the account supports it
Connect application fees Platform revenue is a fee on top of processing, and the liability side differs by charge type Decide fee and liability together, at charge-type choice (connect.md)

Output Gates

Before delivering an integration, a code sample, or a call that moves money:

  • Did I say whether this runs against test or live data, and does it respect live_mode_policy?
  • Does every write that moves money carry an idempotency key derived from a business identifier?
  • Is the amount an integer in the right minor unit for that currency, computed without floats?
  • Is there a named webhook event that completes this flow, and is the handler idempotent by event.id?
  • Does the failure path say what the customer sees — declined, pending, retried, refunded?
  • Did I strip every secret value and leave the <kind>:<locator> pointer instead?
  • Did anything durable come out of this session — a price, an endpoint, an incident, a decision, a dispute outcome? Then it is written to its box in memory.md, with its ## Boxes line, before the session ends.

Configuration

User-dependent variables. Defaults apply until the user states a preference; store them in ~/Clawic/data/stripe-api-integration/config.yaml.

Variable Type Default Effect
stack node | python | ruby | php | go | java | dotnet | http http Language of every code example; http means raw requests with no SDK assumed
api_version text (Stripe version date) none (account default) Parameter and object shapes used in examples, and whether metered billing is written with meters or legacy usage records (Rule 7)
default_currency text (ISO 4217) usd Currency of every example and quote, and which exponent Rule 2 applies
billing_model one-time | subscription | marketplace | invoicing | mixed subscription Which guide leads an ambiguous question, and which events the webhook baseline includes
live_mode_policy test-only | confirm-each | free confirm-each Whether a live-key write is emitted at all, and with what confirmation step (Rule 9, Output Gates)
metadata_keys list [] Keys attached to every created object in examples (Rule 4)
tax_handling none | stripe_tax | external none Whether tax parameters appear in create calls and which invoice fields are treated as required (tax.md)
reconciliation_day number (1-28) 5 Day of month for the reconciliation row in the ## Due table (reconciliation.md)

Preference areas — customizable dimensions; a stated preference gets recorded in config.yaml and applied from then on:

  • Tooling — SDK versus raw HTTP, web framework and its raw-body handling, whether the Stripe CLI is available for local forwarding, Elements versus Checkout versus Payment Links — affects every example's shape
  • Conventions — idempotency-key naming scheme, metadata schema, product and price naming, statement descriptor, invoice numbering — affects generated calls and customers.md
  • Platform — account country and entity, presentment currencies, which payment methods are enabled, payout schedule — affects payment-methods.md and reconciliation.md
  • Safety posture — live-mode gating, whether delete and refund calls are emitted at all, approval before anything customer-visible — affects Output Gates and go-live.md
  • Output format — full error handling and retries in samples versus the minimal call, comments, framework scaffolding — affects every code block
  • Integrations — tax engine, analytics and revenue recognition, dunning tooling, fraud tooling, accounting system that consumes payouts — affects tax.md and reconciliation.md
  • Restrictions — PCI scope the user will not exceed, payment methods or regions they refuse, data they will not store — affects sca-3ds.md and payment-methods.md
  • Cadence — reconciliation day, dispute-rate review, API version upgrade window, key rotation interval — affects the ## Due table

Traps

Trap Why it fails Do instead
Fulfilling on the API response The customer closes the tab, the request times out, or the method settles asynchronously — the money is real and the order is not Fulfill on the event, ack fast, deduplicate by event.id (Rule 1)
One webhook endpoint for everything, subscribed to all events Volume you do not handle, a version you did not choose, and one bad handler poisoning unrelated flows One endpoint per concern, explicit event list, pinned version (webhooks.md)
amount * 100 everywhere Correct for USD and EUR, 100x wrong for JPY and KRW, 10x wrong for KWD and BHD Look up the exponent per currency (Rule 2)
Storing the subscription state in your own database as the truth Stripe changes state on its own schedule — renewals, retries, cancellations at period end Your database mirrors; Stripe decides; the events reconcile the two
Deleting a price or product to change it Prices are immutable in the parts that matter, and live subscriptions point at them Create the new price, migrate subscriptions deliberately (pricing-models.md)
Testing only the happy path in test mode The expensive bugs are all in renewal, retry, dispute and payout paths Test clocks for time, deliberate declines for failure (testing.md)
Treating a refund as a dispute cure Refunding after the dispute is filed loses both the money and the fee, and can look like double repayment Refund before the dispute if the signal arrived early; otherwise fight or accept, never both (disputes.md)
Retrying an off-session charge that asked for authentication It will keep failing; the issuer wants the cardholder Bring the customer back on-session (sca-3ds.md)
Reconciling by summing charges Ignores fees, refunds, disputes, transfers and conversion; the number never matches the bank Sum balance transactions per payout (Rule 8)
Using the same webhook secret across endpoints or environments A test event verified by a live handler is an event you invented One secret per endpoint, resolved from the environment, never stored (go-live.md)
Building a marketplace on direct charges "because it is simpler" Charge type sets fee flow, dispute liability and who owns the customer relationship — changing it later is a migration Decide from liability and reporting first (connect.md)
Rotating keys by creating a new one and forgetting the old The old key keeps working, and it is the one that leaked Roll, deploy, verify traffic on the new key, then revoke — with a date in ## Due (go-live.md)

Where Experts Disagree

  • Checkout versus Elements. Hosted Checkout wins on conversion features you do not have to build — wallets, local methods, SCA handling, address and tax collection — and loses on control of the page. Elements wins when the payment step is inside a product flow you own. The frontier: if the team would spend more than a sprint re-implementing what Checkout gives for free, that sprint is the cost of control.
  • Store the subscription in your database, or read Stripe live. Mirroring gives fast reads and offline behavior, at the price of a sync bug class that is invisible until renewal. Reading live is always correct and couples your uptime to an API call. Most teams land on mirror-plus-events with a nightly re-sync; a system where entitlement mistakes are cheap can read live.
  • Aggressive dunning versus customer experience. More retries and longer grace periods recover more revenue and irritate more customers, and on some rails each failure costs a fee. The break-even is per-rail and per-price-point, not a preference (dunning.md).
  • 3D Secure on everything versus only where required. Blanket 3DS shifts fraud liability and costs conversion; exemption-first keeps conversion and keeps liability. The frontier is your dispute rate by segment: apply authentication where the losses are, not uniformly (sca-3ds.md).
  • Platform-managed onboarding versus Stripe-hosted. Owning the onboarding UI wins on brand and loses on the endless treadmill of verification requirements across countries. Teams that are not in the compliance business hand it to Stripe.

Security & Privacy

Credentials: this skill calls the Stripe API using keys the user already has in their environment (STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET). It does NOT store, log, copy or transmit those keys, and never writes a key, a signing secret, a client_secret, or card data into ~/Clawic/data/.

External endpoint: https://api.stripe.com/v1/* — customer, payment and product data the user sends is processed by Stripe.

Local storage: account context, catalog ids, webhook endpoint inventory, volume and fee history and generated artifacts stay in ~/Clawic/data/stripe-api-integration/ on this machine; shared entities go to ~/Clawic/data/contacts/, ~/Clawic/data/finances/ and ~/Clawic/data/devices/. Object ids and last-four digits only, no secrets, no PANs.

Guardrails: calls are read-only by default. Anything that moves or destroys money — charge, refund, transfer, payout, subscription cancellation, object deletion — is presented with its blast radius and requires explicit user confirmation, and under the default live_mode_policy: confirm-each a live-key write is never emitted inside a block of read-only examples.

Related Skills

More Clawic skills, get them at https://clawic.com/skills/stripe-api-integration (install if the user confirms):

  • payments — choosing a provider and comparing checkout flows before committing to Stripe
  • billing — provider-agnostic billing systems, revenue recognition, invoicing architecture
  • idempotency — dedup windows and at-least-once design beyond Stripe's key
  • webhook — generic webhook receiver design, retries and queueing
  • unit-economics — turning fee and churn numbers into a margin model

Feedback

Part of Clawic, the verified skill library. Get this skill: https://clawic.com/skills/stripe-api-integration.