Manage account obligationsPrivate preview
Track the credit spend, lifecycle, and balances for your connected accounts.
After you activate the connected account’s CreditPolicy, Stripe creates a FundingObligation that allows you to track how much the account owes you throughout a credit period. The beginning of each period automatically creates a new FundingObligation, triggering an issuing_ event.
The FundingObligation only tracks cleared Transactions and doesn’t include pending Authorisations. For information on pending Authorisations, refer to List all authorisations.
How Credit Policies and Funding Obligations work together
The diagram below shows how Credit Policies and Funding Obligations work together to track credit spend and balances:
Key relationships:
- Platform creates and manages Credit Policies for connected accounts
- Credit Policy defines credit limits and terms for each connected account
- Funding Obligation tracks how much each connected account owes the platform
- Connected Account uses credit based on their Credit Policy terms
To demonstrate the process of applying your platform’s funds to a connected account with a CreditPolicy, let’s say that Barbell (one of Gymbox’s connected accounts) has a 1,000 USD credit limit, and they spend 100 USD on a set of weights. The table below outlines the sequence of events on Stripe:
| Action | Barbell issuing balance | Barbell FundingObligation to Gymbox | Gymbox issuing balance |
|---|---|---|---|
| Barbell starts with a 0 USD balance and no prior spend. Gymbox starts with a 100 USD balance | 0 USD | 0 USD | 100 USD |
| Cardholder makes a 100 USD transaction, which is authorised because Gymbox has sufficient funds. Gymbox’s Issuing account drops by 100 USD as a result of an authorisation hold. | -100 USD | 0 USD | 0 USD |
During auth clearing (usually the next day), Stripe:
| 0 USD | 100 USD | 0 USD |
At the end of Barbell’s credit period, Barbell pays off their FundingObligation to Gymbox. | 0 USD | 0 USD | 0 USD |
Track the FundingObligation Lifecycle
Stripe creates a new FundingObligation on the connected account when the current credit period ends. For example, let’s assume Barbell has a 1 month credit period that ends on the 15th of each month. This means that on the 15th of every month, Stripe:
- Finalizes the
amount_of the currenttotal FundingObligation - Creates a new
FundingObligationfor the new period
FundingObligation status
Every FundingObligation changes status based on the credit period set in the CreditPolicy and the written credit or collections policy agreed to with Stripe and the bank.
A FundingObligation can have one of the following statuses:
- Pending: The
FundingObligationis still accruing spend from the current credit period and theamount_might change.total - Unpaid: The
amount_on thetotal FundingObligationis finalised, as indicated by thefinalized_timestamp. The account needs to fully pay off this obligation by theat due_timestamp.at - Paid: The
FundingObligationis fully paid off by the connected account. - Past due: The
FundingObligationisn’t fully paid and thedue_timestamp has passed. Stripe might report past-dueat FundingObligationsto bank partners. - Charged off : The
FundingObligationhas exceeded the number of days until charge off specified in your written credit or collections policy. When setting up your programme, Stripe configures the number of days until charge off after verifying this value against your written credit policy documentation. You can continue to collect repayment from the connected account after theFundingObligationreaches the charged off state. Stripe might report past-dueFundingObligationsto bank partners. Contact Stripe’s Compliance team by submitting a request through the Change Request form to:- Change the number of days until charge off, as specified in your policy documentation
- Plan to sell your charged-off debt
- Needs refund: The
FundingObligationhas a negativeamount_where the platform owes the connected account. This can only happen when a connected account receives an amount from refunds or won disputes that exceeds the amount spent throughout the credit period.total
The due_ field on the FundingObligation is determined by the credit_ field on the FundingObligation and the days_ field on the CreditPolicy.
Retrieve FundingObligations
Over time, a connected account will have multiple paid off (or past_) FundingObligation instances and at most a single currently pending FundingObligation. To fetch the FundingObligation for the current period, run this command:
Example response
[ { "id": "ifo_123", "livemode": true, "created": 1654628149, "amount_total": 10000, "amount_outstanding": 10000, "amount_paid": 0, "currency": "usd", "status": "unpaid", "due_at": 1654714851, "owed_to": "acct_123", "credit_period_starts_at": 1654625149, "credit_period_ends_at":1654713851, "paid_at": nil, "finalized_at": 1654713860, }, ]
To fetch FundingObligations with a particular status, pass in the specific status value when requesting a list of FundingObligations. This API call retrieves FundingObligations with a status of past_:
Get Transactions for a FundingObligation
Retrieve the list of transactions that contributed to a connected account’s FundingObligation by passing the funding_obligation_for_account parameter in the List all transactions API request:
Example response
{ "object": "list", "url": "/v1/issuing/transactions", "has_more": false, "data": [ { "id": "ipi_123", "object": "issuing.transaction", // various other fields "funding_obligation_for_platform": "ifo_123", "funding_obligation_for_account": "ifo_456", // various other fields }, { "id": "ipi_123", "object": "issuing.transaction", // various other fields "funding_obligation_for_platform": "ifo_789", "funding_obligation_for_account": "ifo_456", // various other fields }, {...} ] }
Summary of webhooks
As a reminder, you can monitor these four webhooks:
issuing_: Triggers whenever acredit_ policy. created CreditPolicyis created, which happens when the capability is requested for the connected account.issuing_: Triggers whenever acredit_ policy. updated CreditPolicyis updated, which can happen when the platform updates the connected account’s policy.issuing_: Triggers whenever afunding_ obligation. created FundingObligationis created, which happens around the beginning of each new credit period for the connected account.issuing_: Triggers whenever afunding_ obligation. updated FundingObligationis updated, which happens whenever the funding obligation changes status or amount fields, or has been updated to indicate repayment.
Pay off an account’s FundingObligation
While the FundingObligation shows you how much is owed by a connected account at the end of the credit period, you’re still responsible for collecting repayment from the connected account. Use Stripe’s Payment Intents API to debit the connected account’s external bank account (or accept a card payment through Stripe Checkout or Stripe Invoicing).
Make sure you record any payments received from the connected account in the account’s FundingObligation to accurately reflect their available credit. Stripe determines whether to approve an authorisation based on an account’s available credit. Stripe might report past-due and charged-off FundingObligations to bank partners.
Collect repayment
You can choose the best mechanism for collecting repayment from your end user, but we recommend that you use Stripe’s Payments APIs to keep all records within Stripe for better reconciliation of each user’s card spend and repayment. After successfully collecting payment, make sure you update the FundingObligation to reflect this. This step doesn’t happen automatically when you use Stripe’s Payments APIs. Stripe determines past_ based on the days_ parameter set in the CreditPolicy. Stripe determines charged_ based on your written credit or collections policy that defines the number of days after a past_ obligation is charged_.
Record repayments in FundingObligation
After collecting payment from a connected account, update their FundingObligation to reflect the repayment. FundingObligations states of unpaid, past_, or charged_ impact how many funds are still available for the connected account to spend. For example, let’s assume Barbell has a 1,000 USD credit limit and they buy a treadmill for 900 USD. Barbell’s FundingObligation has 900 USD as the amount_ owed, and they have 100 USD of available credit left to spend until they start paying off what’s owed.
Let’s say Barbell pays back 500 USD to Gymbox at the end of the credit period. Gymbox must update Barbell’s FundingObligation to reflect the repayment. This update decreases the amount_ on the FundingObligation to 400 USD and increases Barbell’s available credit from 100 to 600 USD.
Let’s say Barbell’s credit terms specify a 90-day period post due_ for the amount_ on the FundingObligation to be charged off. On past_ over 90 days, Barbell’s amount_ of 400 USD is charged off. 30 days after charging off the amount_ on the FundingObligation, Gymbox receives a 100 USD payment from Barbell. Gymbox needs to record this repayment with the /pay endpoint to reduce the charged off amount_ on the FundingObligation. This increases the available credit from 600 to 700 USD. If Gymbox closes Barbell’s credit line and reports the reason before collecting in full, the charged off amount_ persists and subsequently recovered amounts can no longer be applied to reduce the amount_.
Example response
{ "id": "ifo_123", "status": "unpaid", "amount_total": 90000, "amount_outstanding": 40000, "amount_paid": 50000, "owed_to": "acct_123", // other fields }
This API call increases the amount_ and decreases the amount_ on the FundingObligation. When amount_ on a FundingObligation, Stripe updates the status of the obligation to paid, regardless of the previous state being unpaid, past_, or charged_. These updates trigger an issuing_ event.
We recommend that you automate both the process of collecting repayment and the process of updating the FundingObligation, and combine them into sequential calls. That way, immediately after you successfully collect repayment, you update the connected account’s FundingObligation to inform Stripe to increase their available credit.
Update the paid amount on the FundingObligation
If you make an erroneous repayment or want to update the connected account’s amount_ for another reason, you can do it with the /pay endpoint using the amount_ field.
Example response
{ "id": "ifo_789", "status": "unpaid", "amount_total": 90000, "amount_outstanding": 45000, "amount_paid": 45000, "owed_to": "acct_123", // other fields }
This sends an issuing_ event.
Update metadata on FundingObligations
You can update the metadata on a FundingObligation to associate additional data with a FundingObligation. For example, you might want to record the OutboundPayment ID that corresponds to a repayment.
Example response
{ "id": "ifo_789", "status": "unpaid", "amount_total": 90000, "metadata": { "repayment_id": "obp_1NUy3y2eZvKYlo2C15gktUET" }, "owed_to": "acct_123", // other fields }
This sends an issuing_ event.
Available credit
Stripe doesn’t currently provide a field that shows the connected account’s available credit balance. You can compute this number through the following formula:
available credit = credit_ - sum(FundingObligation.)1 |
The funds available for a CA to spend at all times is available credit and issuing balance.
1sum(FundingObligation.) is shorthand for you to sum up the amount_ on all FundingObligations in the connected account.
Track the flow of funds
While it’s not necessary for giving your connected accounts access to a credit account, you might want to track the state of authorisations, transactions, and transfers created when a connected account spends funds extended from your platform.
Assume the following starting state:
| Account | Issuing balance |
|---|---|
| Gymbox Issuing Account (Platform) | 70 USD |
| Barbell Issuing Balance (Connected Account) | 0 USD |
Authorisations
Barbell, who has a CreditPolicy with a credit_ of $100 setup with Gymbox, spends $10. This results in a $10 authorisation on Barbell’s account:
{ "id": "iauth_1JVXl82eZvKYlo2CPIiWlzrn", "object": "issuing.authorization", "amount": 1000, "currency": "usd", "approved": true, "authorization_method": "online", "balance_transactions": [ { "id": "txn_1234XYZ", "object": "balance_transaction", "amount": -1000, "type": "issuing_authorization_hold", ... } ], "card": {...}, ... }
Simultaneously, this generates a hold on Gymbox’s issuing balance for the same amount, making sure that the funds are reserved and can’t be used for transactions by Gymbox’s other connected accounts:
{ "id": "txn_1Mgr6fXpL7qsPGZtDwrMkq3S", "object": "balance_transaction", "amount": -1000, "available_on": 1677682692, "created": 1677682692, "currency": "usd", "description": "Platform hold for authorization (account: acct_1MgC5JRcH5icH3Nz, authorization: iauth_1Mgr6dRcH5icH3NzezZCHnJF)", "exchange_rate": null, "fee": 0, "fee_details": [], "net": -1000, "reporting_category": "issuing_authorization_hold", "source": { "id": "iph_1Mgr6eXpL7qsPGZtAMb7x0N6", "object": "issuing.platform_hold", "amount": 1000, "currency": "usd", "originating_account": "acct_1MgC5JRcH5icH3Nz", "originating_authorization": "iauth_1Mgr6dRcH5icH3NzezZCHnJF", "originating_balance_transaction": "txn_1Mgr6dRcH5icH3NzYGRkgcn7" }, "status": "available", "type": "issuing_authorization_hold" }
The balance is now:
| Account | Issuing balance |
|---|---|
| Gymbox Issuing Account (Platform) | 60 USD |
| Barbell Issuing Balance (Connected Account) | -10 USD |
Transfers & transaction captures
Before Issuing authorisations are captured and Issuing transactions are created, funds are transferred to the connected accounts. Then, holds are released from the platform.
On Barbell’s account, the authorisation has been updated and closed, releasing the held funds:
{ "id": "iauth_1JVXl82eZvKYlo2CPIiWlzrn", "object": "issuing.authorization", "amount": 1000, "currency": "usd", "approved": true, "authorization_method": "online", "balance_transactions": [ { "id": "txn_1234XYZ", "object": "balance_transaction", "amount": -1000, "type": "issuing_authorization_hold", ... }, { "id": "txn_4t355646t54w2", "object": "balance_transaction", "amount": 1000, "type": "issuing_authorization_release", }, ], "card": {...}, "status": "closed", "transactions": [ { "id": "ipi_1032HU2eZvKYlo2CEPtcnUvl", "object": "issuing.transaction", "amount": -1000, "authorization": "iauth_1JVXl82eZvKYlo2CPIiWlzrn", "balance_transaction": "txn_1345r1KCr4trgtrg0WfNdUCbG1w", ... } ... }
The funds held on the platform’s account are also released:
{ "id": "txn_1Mgr6fXpL7qsPGZtDwrPz7bA", "object": "balance_transaction", "amount": 1000, "available_on": 1677682692, "created": 1677682692, "currency": "usd", "description": "Released platform hold for authorization (account: acct_1MgC5JRcH5icH3Nz, authorization: iauth_1Mgr6dRcH5icH3NzezZCHnJF)", "exchange_rate": null, "fee": 0, "fee_details": [], "net": 1000, "reporting_category": "issuing_authorization_hold", "source": { "id": "iph_1Mgr6eXpL7qsPGZtAMb7m8Z3", "object": "issuing.platform_hold", "amount": -1000, "currency": "usd", "originating_account": "acct_1MgC5JRcH5icH3Nz", "originating_authorization": "iauth_1Mgr6dRcH5icH3NzezZCHnJF", "originating_balance_transaction": "txn_1Mgr6dRcH5icH3NzYGR7bA4c" }, "status": "available", "type": "issuing_authorization_hold" }
Stripe transfers funds from Gymbox to Barbell’s Issuing account and a Transfer object is created:
{ "id": "tr_3JeQsp2eZvKYlo2C13DagtB0", "object": "transfer", "amount": 1000, "amount_reversed": 0, "balance_transaction": "txn_1032HU2eZvKYlo2CEPtcnUvl", "created": 1646912059, "currency": "usd", "description": null, "destination": "acct_1032D82eZvKYlo2C", "livemode": true, "metadata": {}, "reversals": { "object": "list", "data": [], "has_more": false, "url": "/v1/transfers/tr_3JeQsp2eZvKYlo2C13DagtB0/reversals" }, "reversed": false, "source_transaction": null, "issuing_transaction": "ipi_1032HU2eZvKYlo2CEPtcnUvl", "metadata": {}, "source_balance": { "type": "issuing", }, // New destination_balance returned field links to the BT on the connected account side "destination_balance": { "type": "issuing", "issuing": { "balance_transaction": "txn_123", }, }, // ... other fields ... }
This sequence of hold, release and transfer happens before Stripe creates the associated Issuing transaction. The balance is now:
The balance is now:
| Account | Issuing balance |
|---|---|
| Gymbox Issuing Account (Platform) | 60 USD |
| Barbell Issuing Balance (Connected Account) | 0 USD |
If there is no original authorisation for a transaction and the connected account doesn’t have sufficient funds to cover it, the platform balance transfer and transaction creation flow still occurs.
Refunds
When a connected account receives a refund, Stripe attempts to determine whether it pertains to a transaction that’s funded from that connected account’s balance or platform’s account. If Stripe determines that it’s funded from the connected account’s balance, the funds return to the connected account’s balance. If the transaction is funded from the platform’s account (for example, from the connected account’s credit line), the connected account’s FundingObligation reduces by that amount. The refund is then transferred to the platform’s account because the platform already paid Stripe for the transaction on behalf of the connected account.
Let’s say Barbell has a 100 USD FundingObligation. If the amount is refunded, then:
- Barbell’s
FundingObligationdecreases from 100 to 0 USD - The 100 USD is transferred to Gymbox’s Issuing account, increasing their platform balance by 100 USD
It’s possible for the amount_ on a FundingObligation to be negative, which happens if the only transaction in a credit period is a refund and there’s no other card spend. The FundingObligation indicates a status of “Needs refund.” A negative FundingObligation can occur if there’s card spend but the amount of total refunds is higher than the total card spend.
Disputes
When a customer disputes a credit spend transaction on a connected account, the dispute follows the process outlined in Issuing disputes. Lost disputes result in no action (no credits are issued to the connected account). Won disputes issue a credit to the connected account in the same manner as described in the Refunds section.
Authorisation declines
Authorisations made on a connected account with a CreditPolicy could be declined for the following reasons:
- The connected account attempts to spend beyond its available credit limit. In this instance, the connected account might have unpaid
FundingObligationsthat have reduced its available credit. Make sure that your connected account’sFundingObligationsare always up-to-date to preventAuthorizationdeclines. - Your available platform Issuing account reaches zero, and the available Issuing balance of your connected account is also at zero. Top-up your Issuing account with sufficient funds to avoid declines.