# Introduction

Credit Coop is a pioneering onchain structured finance protocol that reimagines how businesses access capital. Our platform leverages blockchain technology to transform future cash flows into leverageable assets, enabling companies to unlock growth without dilution.&#x20;

At the core of Credit Coop is our innovative Secured Line of Credit, powered by the Spigot smart contract. This groundbreaking technology allows businesses to collateralize their future revenues, creating a novel form of programmatic recourse that enhances capital efficiency for borrowers while providing unparalleled security for lenders.

Key features of the Credit Coop protocol include:

* **Programmatic Recourse:** Our Spigot smart contract automates the collection of borrowers' cash flows, eliminating the need for trust in repayments and providing real-time visibility into loan performance.
* **Flexible Collateralization:** Credit Coop supports a "mix-and-match" approach to collateral, allowing businesses to leverage both traditional assets and future cash flows to secure credit.
* **Onchain Execution:** All lending activities are executed onchain, ensuring transparency, efficiency, and programmability.
* **Composability:** Our protocol is designed to be interoperable with existing DeFi ecosystems, allowing for the creation of complex financial products and services.

The Credit Coop V1 protocol focuses on providing capital-efficient financing solutions for businesses while offering attractive, secure lending opportunities for investors. As we continue to evolve, we're committed to expanding our offerings to meet the diverse needs of both borrowers and lenders in the rapidly growing onchain credit market.

This documentation will guide you through the intricacies of the Credit Coop protocol, from its core concepts to detailed technical specifications. Whether you're a borrower looking to unlock growth, a lender seeking secure yield opportunities, or a developer interested in building on our platform, you'll find the information you need to leverage the full potential of Credit Coop.

Join us as we redefine the future of structured finance and unlock new possibilities for growth in the digital economy.


# Get in Touch

General inquiries: <contact@creditcoop.xyz>

BD inquiries: <bd@creditcoop.xyz>


# Secured Line of Credit

The first instance of debt-based financing issued natively onchain

The Secured Line of Credit is a credit facility secured by onchain cash flows and/or asset collateral.

**Benefits for Borrowers**

* Flexible financing for OpEx and longer term growth initiatives with no fixed repayment schedule
* On-demand liquidity. Only use what you need, when you need it
* Leverage future cash flow/revenue (assets you don’t even have yet) to drive growth
* Syndication - the credit line does not have to be solely in USDC from one lender, it supports multiple assets and multiple lenders for each Secured Line of Credit. <br>

**Benefits for Lenders**

* Assess borrower risk and price accordingly via lender-specific interest rates&#x20;
* Receive a return on deposited capital even if funds are not drawn down
* Withdraw deposited capital on-demand if funds aren’t drawn down by a Borrower
* A Line of Credit is collateralized by the borrower's cash flows via the Spigot to service debt&#x20;
* Recourse via priority repayment, programmatically enforced

*Not sure what a revolving Line of Credit is? For a basic overview from TradFi, see* [*here*](https://www.investopedia.com/terms/r/revolvingcredit.asp)*.*&#x20;


# Line of Credit Features (v1)

In this section we introduce the main features of a Line of Credit as available in its first version.  An enhanced version will be released soon so expect some updates soon.

There are currently two ways to secure the Line of Credit, using borrower cash flows and/or asset collateral deposited by a Borrower.

<details>

<summary>Revenue-Based Financing</summary>

The revenue-based financing approach, facilitated by the [Spigot](/about-our-products/the-spigot), automatically collateralizes a percentage of the Borrower's revenue to repay the line. It provides security through having Trustless Recourse to the cash flow stream of the Borrower in any event of default.

</details>

<details>

<summary>Asset-Based Lending</summary>

This more conventional approach takes tokens deposited by a Borrower and uses their spot price to calculate a collateral ratio. If the collateral ratio falls below the minimum required then the loan becomes eligible for liquidation.

</details>

{% hint style="info" %}

{% endhint %}


# Cash Flow Financing

Using a Borrower cash flow streams to repay and secure Credit Lines.

The Spigot secures onchain cashflows and automatically repays interest and principal to Credit Lines.

If a Borrower hasn’t fully repaid its Credit Lines by an agreed Deadline or is otherwise in default, the Spigot will start to escrow 100% of the value from a Borrower's Revenue Contract.

This is cryptonative secured lending. This is the first time that revenue-based credit has been originated and serviced fully onchain with no intermediaries.&#x20;

Benefits include:

* Lender protection is enforced onchain in a programmatic manner&#x20;
* Lenders have confidence that their loan is backed by verifiable onchain revenues&#x20;
* Borrowers can take out larger loans at lower interest rates
* Borrowers can gain access to the most flexible, low-rate loans with no upfront collateral

<figure><img src="/files/2sNrFtfjz7z0sqoja9G9" alt=""><figcaption></figcaption></figure>


# Deploying a Secured Line of Credit

{% hint style="info" %}
Much of what follows is pre-configured and/or automated for users of the App.
{% endhint %}

A Borrower and a first Lender agree on some fundamental aspects:

<details>

<summary>Deployment parameters of the Secured Line of Credit</summary>

* The deadline for repayment of the Line
* The minimum collateral ratio&#x20;
* the revenue split (%) &#x20;
* the borrower address&#x20;

</details>

<details>

<summary>Revenue-Based Lending</summary>

During Line deployment, a Spigot can be attached to a Borrower Revenue Contract, i.e. a smart contract owned and operated by the Borrower which will be used to secure the overall Line and automatically repay Credit Lines .&#x20;

The single Spigot deployed can attach to multiple Borrower Revenue Contracts.&#x20;

The Borrower and the first Lender must agree:

* The address of the Borrower **Revenue Contract**
* The initial **default split** of **Revenue Tokens** between the Borrower and Lenders (i.e. of the tokens from the Revenue Contract)
* The **trading router** which, if needed, will convert the Borrower’s Revenue Tokens into the Credit Tokens actually borrowed and later repay *(Credit Coop has already arranged this but the parties must agree anyway)*
* The **whitelisted functions** that the Borrower is allowed to perform on the Revenue Contracts whilst the Spigot is attached so that the Borrower operate as usual
* The **contract address of the Spigot** [**Operator**](/about-our-products/the-spigot/spigot-roles/operator), an address through which the Borrower can still conduct business as usual on the Revenue Contract within the constraints of the whitelisted functions. This is also the address through which the Borrower receives all remaining Revenue Tokens not escrowed in the Spigot for the benefit of Lenders.

</details>

<details>

<summary>Asset Collateral</summary>

If Asset Collateral is to be posted, the Borrower and the Lender must agree:

* The collateral token(s), which must be whitelisted by the Servicer&#x20;
* The minimum collateral ratio to be maintained, if any.

</details>


# Core Lending Functionality

Drawdowns, extending further credit and repayments

{% hint style="info" %}
As a reminder, the term 'Line of Credit', Secured Line', 'Secured Line of Credit', 'Line' or 'LoC' means a single credit facility for a single Borrower. The Borrower can draw down on any number of individual Credit Lines (aka Credit Positions) made available by any number of Lenders at any interest rates and denominated in any token.
{% endhint %}

<details>

<summary>Lender deposits funds | Credit Line is created</summary>

A Lender can propose a Credit Line at any time.

The deposit succeeds and the Credit Line is created if both Borrower and Lender consent to terms and mutually sign a transaction regarding:

* The interest rates (drawn rate & facility rate)&#x20;
* The token being borrowed (aka Credit Token)
* The amount of the Credit Token being deposited by the Lender

The deadline/term of the Line as well as the security/collateral parameters are the same for all Credit Lines and are set at deployment\*. \
\
\**\[In the next version, individual Credit Lines will have separate deadlines, rather than the Line of Credit].*

</details>

<details>

<summary>Borrowing</summary>

A Borrower can draw down at any time from any Credit Line as long as the Line of Credit as an Active status

</details>

<details>

<summary>Lender deposits more funds to an existing Credit Line (existing Lender)</summary>

A Borrower and a Lender can agree to increase the credit available on the terms already agreed by making further deposits to an existing individual Credit Line.

</details>

<details>

<summary>New Lender deposits funds</summary>

New Lenders can deposit funds once terms are agreed with the Borrower in the same way as mentioned above.

They can offer funds in a different token or they can offer different interest rates compared to existing Lenders for the same token.

They do however have to respect the same Deadline as existing Credit Lines *\[changing in V2]*.

The Borrower and new Lender must mutually consent to terms as mentioned above.

</details>

<details>

<summary>Interest Rates</summary>

A Borrower and a Lender must agree on two borrowing rates:

1. The Drawn Rate, i.e. the interest rate charged to a Borrower on actual borrowed / drawn down funds
2. The Facility Rate, i.e. the interest rate charged to a Borrower on the [remaining funds available, but not yet drawn down](#user-content-fn-1)[^1].

The parties can agree on new rates at any time. This can happen for the purpose of refinancing or if the Line risks becoming impaired.

</details>

<details>

<summary>Accrued Interest Calculation</summary>

Interest on a Credit Line starts accruing to a Lender at the Facility Rate as soon as a Lender makes a deposit. This is to compensate the Lender for making available the capital even though the Borrower hasn't yet actually borrowed it.

Interest starts accruing at the *Drawn Rate* on any funds that are drawn down by a Borrower as soon as they are drawn down.

Any credit that is still available to a Borrower but not yet drawn down will accrue interest at the Facility Rate which is generally lower than the Drawn Rate.

Interest is charged anytime balances are updated (e.g. a new Lender adding or withdrawing credit or a Borrower borrowing or repaying). All these events will trigger the recalculation of the accrued interest that is owed on the credit line whose balance has changed.

</details>

<details>

<summary>Repaying Credit Lines</summary>

A Borrower, or any other party, can deposit Credit Tokens (i.e. the token initially lent out by a Lender) at any time to repay lenders. These tokens are then available to be withdrawn by Lenders.

If the Line of Credit is Revenue-Based, i.e. secured by a Spigot, then [further possibilities](/about-our-products/secured-line-of-credit/secured-line-of-credit/revenue-based-lending-operations) for repayment exist.

</details>

<details>

<summary>Withdrawals by Lenders</summary>

If funds are available on a Credit Line, i.e. not all drawn down, a Lender can withdraw at any time.

</details>

<details>

<summary>Closing a Line of Credit</summary>

A Borrower can deposit funds and repay at any time and subsequently close a Credit Line as long as the principal and interest have been fully repaid.

When a Borrower closes the last available Credit Line, the status of the Line of Credit changes to repaid and no more Credit Lines can be proposed.

</details>

<details>

<summary>Line Health Status</summary>

A healthcheck function can be run at any time to discover and/or update the status of a Line and which can be programmed to take into account predefined covenants such as a minimum collateralization ratio for Asset Collateral (if used).

There are five types of status: uninitialized, active, repaid, liquidatable, and insolvent.&#x20;

</details>

<details>

<summary>Borrower Credit Events</summary>

If a Borrower doesn't fully repay all Credit Lines by the deadline, the Borrower has defaulted on its obligations and the status may change to liquidatable.

See [here](/about-our-products/secured-line-of-credit/secured-line-of-credit/loan-impairment-and-lender-recourse) for further details, including breaches of the Min Collateral Ratio.

</details>

[^1]: often referred to as 'headroom'


# Revenue-Based Lending Operations

In addition to the core lending operations, a Revenue-Based line of credit has some extra features.

{% hint style="info" %}
A Spigot is automatically deployed with a Line of Credit according to terms agreed.

Tokens from Borrower Revenue Contracts are escrowed by the Spigot to repay and secure the Line of Credit according to the split that's agreed up front.
{% endhint %}

### Borrower Repayments and Lender Withdrawals

<details>

<summary>Use Tokens from Borrower Revenue Contracts to repay Credit Lines</summary>

Tokens are from time to time pulled from a Revenue Contract and made available in the Spigot.

These tokens can be used straightaway to repay Credit Lines according to their order in the repayment queue. &#x20;

As part of this, the system checks that the tokens from the Borrower Revenue Contracts are the same tokens actually needed to repay the Credit Line. If need be, and using a decentralised exchange, it exchanges them to the required token.<br>

</details>

<details>

<summary>Store Tokens from Borrower Revenue Contracts in Reserves</summary>

Instead of repaying a Credit Line straightaway, tokens from Borrower Revenue Contract can be stored for later.  If they need to be exchanged then the system will do so.  What results is a store of Reserve Tokens that both secures the Line of Credit and is on standby to repay Credit Lines as and when.

This feature is useful for a Borrower for several reasons

* Gain flexibility in managing repayments based on the current state of the system and the source of repayment funds.
* Time the exchange of tokens if you have a view on potential price movements.
* Increase the Collateral Ratio *\[Reserve Tokens will be considered as Collateral in the next version when calculating the Collateral Ratio of the Line of Credit.]*

</details>

*See* [*here*](/developer-material/v1-developer-material/repaying-debt) *for a more comprehensive overview of all the repayment options*

### Other Features

<details>

<summary>Adding an additional Revenue Contract to a Secured Line of Credit</summary>

A Borrower can propose additional Revenue Contracts to further secure the repayment of debt and/or to replace a Revenue Contract already providing security. The Servicer can assist here.

</details>

<details>

<summary>Updating the whitelisted functions that a Borrower can call on a Revenue Contract</summary>

It's possible to update the whitelisted functions that a Borrower is allowed to perform on a Revenue Contract. As a reminder, these are the functions that the Borrower can still call on those contracts for business as usual whilst they are providing Revenue Tokens to repay debt. The Servicer can assist here.

</details>

<details>

<summary>Updating the split of Revenue Tokens between a Borrower and Lenders</summary>

The split of Revenue Tokens between a Borrower and Lenders changes if (1) the parties to the lending agreement wish to change the split or (2) programmatically based upon the status of the Line of Credit.&#x20;

</details>

<details>

<summary>Automatic release of Spigot after full debt repayment or during a credit event</summary>

Control of an entire Spigot is automatically released back to the Borrower (if all Credit Lines have been been fully repaid). This enables a Borrower to easily reuse a Spigot and it's attached Revenue Contracts as security for a new Line of Credit.\
\
If however the Line status becomes liquidatable, control of the Spigot can pass automatically to the Servicer. See[ Loan Impairment and Recourse](/about-our-products/secured-line-of-credit/secured-line-of-credit/loan-impairment-and-lender-recourse) for what happens next.

</details>

<details>

<summary>Removing control over a single Revenue Contract</summary>

Control over a ***single*** Revenue Contract can be transferred back to a Borrower after a Line of Credit secured by that Revenue Contract has been repaid. The Revenue Contract in this case is 'removed' from the Spigot, the reverse action of being 'added' to the Spigot earlier.

</details>

<details>

<summary>Reusing a Spigot for a new Line of Credit</summary>

When all Credit Lines have been repaid and closed and a Spigot released back to a Borrower, the Borrower can rollover the already configured Spigot and use it as security for a new Line.

\
Continuity is an important feature for future products we will build on top of Spigot. This makes it easier to continue reusing the same Spigot and make setting up new lines easier and cheaper (less gas costs) and less likely for human error.

</details>

<details>

<summary>Liquidating a Spigot</summary>

If a Borrower doesn't repay and close all Credit Lines by the Deadline, the Borrower has defaulted and the status of the Line may be changed to liquidatable.

The Servicer can proceed to liquidate whatever collateral/security is available by sweeping the Spigot which henceforth receives 100% of Revenue Tokens due to the impaired status of the facility.

See the [dedicated section](/about-our-products/secured-line-of-credit/secured-line-of-credit/loan-impairment-and-lender-recourse) for more information about credit events.

</details>


# Collateral Operations

Features for managing asset collateral that the parties may agree is also required to secure a line

<details>

<summary>Whitelisting a new collateral token</summary>

Any ERC-20 or ERC-4626 tokens that a Borrower wishes to use as collateral must be whitelisted ('enabled') by the Servicer. *\[The scope of collateral will widen in our next version to include LP tokens].*

</details>

<details>

<summary>Borrower adds Collateral</summary>

A Borrower can at any time deposit whitelisted tokens as collateral after which the collateral ratio is updated.

</details>

<details>

<summary>Collateral Ratio</summary>

The ratio of the value of Collateral securing all the Line of Credit to the value of the Borrower's Total Outstanding Debt. *\[Soon this will include not only Collateral deposited by a Borrower in the traditional sense but also Reserves from the capture of Borrower Revenue by the Spigot]*

</details>

<details>

<summary>Borrower withdraws Collateral</summary>

A Borrower can withdraw any amount of Collateral as long as the Min Collateral Ratio is maintained. After all Credit Lines have been fully repaid and closed, the status of the Line of Credit becomes 'repaid' and the Borrower can withdraw all remaining Collateral.

</details>

<details>

<summary>Borrower transfers Collateral to a new Line of Credit</summary>

After all Credit Lines have been fully repaid and closed, the status of the Line of Credit becomes 'repaid' and a Borrower can transfer (roll over) Collateral to a new Line without needing to withdraw it and deposit it again.

</details>

<details>

<summary>Servicer liquidates Collateral</summary>

When certain conditions are fulfilled the status of a Line may change to liquidatable. Only if the status is liquidatable, the Servicer is programmatically granted the permission to liquidate Collateral on behalf of Lenders.

</details>


# Credit Events

Borrower default and what a Lender can do about it

There are two conditions presently that are considered as actionable credit events on a Secured Line of Credit:

* Failing to make interest and principal repayments to Credit Lines in whole and on-time
* Breaking a covenant in the loan terms such as Min Collateral Ratio

In the event of either of the above events,  the status of the Line of Credit may be changed to 'liquidatable' and 100% of Revenue Tokens can be used henceforth to repay Credit Lines.  These two actions are automatically triggered.

After that, recoverable assets will be:

<details>

<summary>Any remaining funds not drawn down</summary>

Equals

The amount deposited by Lenders

\+

any accrued interest repaid by the Borrower to Credit Lines but not yet withdrawn by Lenders

\-

the amount that a Borrower has drawn down

</details>

<details>

<summary>Funds recoverable from Collateral deposited by the Borrower</summary>

In addition, Collateral put up as security for the loan will be liquidated.

</details>

<details>

<summary>Funds recoverable via the Spigot</summary>

In addition, if deployed, the Spigot contract will siphon 100% of Revenue Tokens that continue to be available from the Borrower's Revenue Contracts.

</details>

If a Borrower is permanently incapable of repaying debt then the status of the Line will be changed to 'insolvent' by the Servicer.

Lenders and Borrowers can of course at any point renegotiate terms.


# The Spigot

A groundbreaking innovation for the onchain financial ecosystem.

The Spigot is a novel smart contract governing the secure split of onchain cash flows between two or more parties according to an agreement between the parties.

Most importantly, it provides for Trustless Recourse in the event that one party (the obliging party) doesn't fulfil its obligations to the other party.

{% hint style="info" %}
In the case of a Secured Line of Credit used for example as an opex loan, the Spigot enables Lenders to automatically receive a portion of a Borrower's revenue streams in order to secure and automatically repay a loan until Lenders have been fully repaid as per the agreed upon terms.
{% endhint %}

<figure><img src="/files/hd63LyhorX1no1Kebk6R" alt=""><figcaption></figcaption></figure>


# Key features of the Spigot

A Spigot's purpose is to provide Trustless Recourse for Secured Agreements

Whilst the first usage of the Spigot is to provide security for Lines of Credit, later products will be built around it for things like selling off collateral or securitizing future revenue.

A Spigot is automatically deployed with a Secured Line of Credit in order to capture cash flows from Borrower Revenue Contracts to secure and repay Credit Lines. Please refer to [Revenue-Based Financing](/about-our-products/secured-line-of-credit/secured-line-of-credit/revenue-based-financing) for an overview of the features that the Spigot enables.

The rest of this section focuses on the Spigot more generally.

<details>

<summary>Ownership</summary>

The Spigot Owner is a party that is owed 'something'.

It has direct control over Revenue Contracts belong the the party that owes (the 'obliging party', which we will call the Operator here).&#x20;

The Operator, the obliging party that owes the 'something' and is generating the revenue, cannot change where the cash flow streams go.&#x20;

The Owner will receive a share of these cash flow according to an agreed 'split'.

</details>

{% hint style="warning" %}
*An attack vector could be for the Operator to divert revenue away from being received by the Revenue Contracts. This is unavoidable but mitigated largely by eligibility criteria and B2B due diligence processes.*
{% endhint %}

<details>

<summary>Value Capture</summary>

The Spigot captures a fixed percentage of cash flows from a Revenue Contract under its control and escrows it for the Owner.

The percentage split of the cash flows ('Owner Split') is based on rules and events defined by the parties at the outset. For example, the parties can agree to escrow more or less revenue when a defined trigger event occurs.

</details>

<details>

<summary>Value Transmission</summary>

Value escrowed for the Owner is available to be withdrawn on demand.

*An example of value transmission is the paying back of interest and principal, or payments related any other additional conditions agreed between the parties from the outset of the agreement.*

</details>

<details>

<summary>Permissions</summary>

Although a Revenue Contract is collateralized and controlled by a Spigot, the Operator (the obliging party) can still manage its products/protocol.

It can use whatever functions it needs to ensure that revenue can still be generated and business can carry on as usual.

We call these permitted functions the 'whitelisted' functions.

</details>

<details>

<summary>Programmatic Recourse</summary>

In the event that the Operator (the obliging party) defaults on an agreement, in addition to a first possibility that 100% of the value accruing to Revenue Contracts flows to the Owner, the Owner role can also be transferred to 3rd party arbitration or permanently to other beneficiary parties.

*If the agreement is a Secured Line of Credit for example, this can result in the full amount of value of a Revenue Contract being transferred from a Borrower to Lenders until the Line is repaid.*

</details>

If you want to use the Spigot independently or develop a custom lending products or smart contract integrating a Spigot then please contact us to discuss. An overview of the Spigot's external functions and methods is available in the [developer](https://docs.creditcoop.xyz/developer-documentation/introduction) documentation.


# Spigot Roles

There are two important roles for each deployment of a Spigot

The Owner and Operator are addresses controlled by the parties involved in the agreement for which the Spigot is providing automated repayment and security.

The flow of Revenue Tokens from a Borrower's Revenue Contract and its split between the Owner and the Operator are illustrated below.

<figure><img src="/files/baFdzenCK8HP25Ef5oo0" alt=""><figcaption></figcaption></figure>

Please head the to next section for further detail


# Owner

The Owner is an address through which the Spigot is managed for the benefit of one or more actors (e.g. Lenders) based upon programmable events.

The Owner has the ability for example to add a revenue source, control the flow of revenue and to split the revenue between parties (including itself) based upon programmable events.

{% hint style="info" %}
In the Secured Line example, the Owner is the Line of Credit smart contract acting for the benefit of Lenders except in the event of loan impairment when the Servicer takes the Owner role in order to work out the loan.
{% endhint %}

Very importantly and as part of the security features, the Owner can whitelist what functions an Operator (the obliging party in an agreement) can still call on a Revenue Contract. This allows the Operator to carry on business as usual.

The Spigot is programmatically (trustlessly) released to a new Owner when certain conditions are fulfilled.

{% hint style="info" %}
For example, the Spigot is released and its ownership transferred back to a Borrower when a Line of Credit has been fully repaid. If the loan becomes impaired, the entire revenue stream can be diverted for the benefit of Lenders.
{% endhint %}

The Owner can be any externally owned account (EOA) controlled by a private key or it can be a smart contract account that has an associated code that executes when it receives a transaction from an EOA.


# Operator

The Operator is an address through which an obliging party in an agreement is still able to execute whitelisted functions to carry on business as usual related to a Revenue Contract.

As a reminder, during the life of the agreement, the Revenue Contract is controlled by the Spigot Owner for the benefit of one or more further parties to the agreement.

The Operator is also the address which receives all remaining Revenue Tokens that are not escrowed in the Spigot for the benefit of the Owner.


# User Documentation (v1)

For End Users to discover step by step the first version of the Secured Line of Credit

User Documentation mentioned here is all available at our[ User Doc Site](https://creditcoop.notion.site/Credit-Coop-User-Documentation-68141d78ffa54a38b4609b42c64bb93c?pvs=4).

<details>

<summary>App <strong>F</strong>AQ</summary>

The App FAQ is available as part of our dedicated User Documentation site. &#x20;

Questions are grouped by stages in the loan life cycle. [Click to discover it!](https://www.notion.so/creditcoop/0755372b767f463cb01e0cf41aeb55e2?v=be40f404e6924029bfdd11f478cc3a31\&pvs=4)

Developers and Integrators accessing the underlying smart contracts directly should also refer to the more detailed [developer docs](https://docs.creditcoop.xyz/developer-documentation/functions-and-methods).

</details>

<details>

<summary><strong>User Journey Guide</strong></summary>

A step-by-step guide through the journey of Line deployment (done by the Servicer), borrowing and lending, repayment and what happens if things don't quite go to plan.

The User Journey Guide is available as part of our dedicated User Documentation site.  [Click to discover it](https://www.notion.so/creditcoop/28f3e4d84a134ea78f6aa0f501686dd7?v=d2459cb84afa40228ff573088a1d0478\&pvs=4)!

</details>

<details>

<summary>Glossary</summary>

For App users, the Glossary explains terms used on the front-end and is available as part of our dedicated User Documentation site.  [Click to discover it!](https://www.notion.so/creditcoop/b9f570048e2841c59c029f3e14469d42?v=45a10c249fc94cbab57ad72bb28c8168\&pvs=4)

Developers and Integrators accessing the underlying smart contracts directly should also refer to the more detailed [developer docs](https://docs.creditcoop.xyz/developer-documentation/functions-and-methods).

</details>

*Developers and Integrators accessing the underlying smart contracts directly should also refer to the more detailed* [*developer docs*](https://docs.creditcoop.xyz/developer-documentation/functions-and-methods)*.*


# User Documentation (v2)

Credit Coop Protocol V2 introduces Vaults, the Vault Curator model, and an updated Credit Line architecture designed for institutional, B2B use.

This section of the documentation covers participant roles, key concepts, fees, and legal reference material applicable to V2. It is intentionally concise. V2 is in active deployment and this documentation will be expanded on an ongoing basis as the protocol matures.

For current protocol parameters, Vault configurations, and Credit Line details, refer to the Interface at [app.creditcoop.xyz](https://app.creditcoop.xyz). Detailed technical specifications and integration material are available to registered participants on request.

For questions not addressed here, contact your Credit Coop representative or reach out at <legal@creditcoop.xyz>.


# Participants & Roles

The Credit Coop Protocol V2 has three participant types: Vault Depositors, Vault Curators, and Borrowers. Each interacts with the Protocol through the Interface in a distinct capacity.

***

### Vault Depositors

Vault Depositors supply Digital Assets to Vaults through the Interface. Vaults are non-custodial pooled smart contract structures that allocate capital across Credit Lines and sources of liquid asset yield.

CMBT Labs does not hold, control, or have access to deposited Digital Assets at any time.

Upon deposit, Vault Depositors receive Vault Tokens representing their pro rata participation in the Vault. Vault Tokens are redeemable for the underlying stablecoin, subject to available liquidity in the Vault.

***

### Vault Curators

Vault Curators manage a Vault by determining how capital is allocated across Credit Lines and sources of liquid asset yield.

Curator responsibilities include:

* Approving borrower deployments within the Vault
* Setting facility parameters, including credit limits and collateral requirements
* Processing deposit and redemption requests

CMBT Labs does not exercise discretion over capital allocation decisions made by Curators. All Curator actions are executed via smart contracts. Curator obligations are further governed by any applicable Vault Curator Agreement.

***

### Borrowers

Borrowers access Digital Assets through one or more Credit Lines via the Interface.

**As a Borrower, you are solely responsible for:**

* Setting collateral and Credit Line parameters in line with the risks you are willing to accept
* Monitoring the Collateral Ratio of each Credit Line on an ongoing basis
* Repaying each Credit Line in full before its Due Date

To avoid liquidation, you may need to deposit additional Collateral and/or repay from Reserves if your Collateral Ratio approaches the applicable minimum threshold. If the Collateral Ratio falls below that threshold, liquidation of Collateral and Reserves will be authorised in accordance with the liquidation mechanics described in the Servicer & Liquidation section.

Borrowers may also configure Revenue Contracts as a repayment source through the Spigot smart contract.

> **Important:** All transactions executed through the Interface are irreversible and final. You are responsible for carrying out your own due diligence before interacting with the Protocol.


# Fees

The Credit Coop Protocol automatically calculates and deducts certain fees. Fee levels may vary per Credit Line or Vault and are displayed on the Interface. No fee requires manual payment — all deductions occur programmatically via smart contract.\
\
The list below is exhaustive.  Not all of these fee types are used.

CMBT Labs does not receive protocol-level fees in its capacity as Interface provider or Servicer.&#x20;

***

### Fee types

**Origination Fee.** Calculated when Digital Assets are deposited to a Credit Line. Deducted automatically from the deposited amount at the time of deposit. Although deducted from the deposit, the Origination Fee is effectively borne by the Borrower, who remains liable for repayment of the full deposited amount plus interest.

***

**Servicing Fee.** Calculated when Digital Assets are repaid to a Credit Line. Deducted from the repayment amount at the time of repayment.

***

**Swap Fee.** Calculated when Digital Assets held in Reserves are converted into the repayment asset required by a Credit Line. Deducted from the proceeds of the swap before those proceeds are applied to the Credit Line.

***

**Early Withdrawal Fee.** Charged when a Vault Depositor or Lender withdraws Digital Assets before the agreed Due Date of the relevant Credit Line. Sent to the Borrower's Wallet. The applicable fee rate is set per Credit Line and displayed on the Interface.

***

**Vault Management Fee.** An annual fee charged on Digital Assets held in a Vault. Calculated and deducted automatically on an ongoing basis.

***

**Vault Performance Fee.** Charged on returns generated by a Vault above an applicable hurdle or benchmark. Calculated and deducted automatically.

***

**Blockchain Fees** Transactions on the blockchain require payment of network fees (e.g. gas charges). These fees are:

* Non-refundable
* Outside CMBT Labs' control — CMBT Labs has no ability to influence their amount
* Variable depending on network conditions at the time of the transaction

You must ensure your Wallet holds sufficient balance to cover both the transaction amount and any applicable blockchain fees before initiating any transaction.

***

> All fee parameters are determined by Credit Coop Protocol governance and smart contract logic. Current fee rates for any Vault or Credit Line are displayed on the Interface at [app.creditcoop.xyz](https://app.creditcoop.xyz).


# Vaults

A Vault is a pooled smart contract structure that accepts stablecoin deposits and allocates capital across Credit Lines and sources of liquid asset yield within the Credit Coop Protocol.

Vaults are non-custodial. CMBT Labs does not hold, control, or have access to Digital Assets deposited into any Vault at any time.

***

### How Vaults work

Vault Depositors supply Digital Assets to a Vault through the Interface. Upon deposit, they receive Vault Tokens representing their pro rata participation, redeemable for the underlying stablecoin subject to available liquidity.

Capital within the Vault is allocated by the Vault Curator across Credit Lines and other liquidity strategies. Vault Depositors do not control individual allocations — that responsibility sits with the Curator.

***

### Protocol parameters and governance

Vault-level configuration and protocol-level parameters — including fee structures, collateral requirements, and credit limits — are determined by Credit Coop Protocol governance processes and encoded in smart contract logic.

No single party, including CMBT Labs, has unilateral control over these parameters. Current Vault and Credit Line configurations are displayed on the Interface at [app.creditcoop.xyz](https://app.creditcoop.xyz).

***

### Related pages

* Participants & Roles — responsibilities of Vault Depositors, Curators, and Borrowers
* Fees — fee types applicable to Vaults
* Servicer & Liquidation — how liquidation works


# Servicer & Liquidation

### The Servicer

The Servicer is a technical and operational role within the Credit Coop Protocol architecture. The Servicer role is modular and may be performed by one or more parties. CMBT Labs may act as Servicer in its capacity as a technical service provider.

The Servicer:

* Executes smart contract interactions in accordance with approved protocol parameters and smart contract logic
* Does not exercise independent discretion over credit decisions, lending terms, or fee structures — these are determined by smart contract logic and protocol governance
* Does not act as a lender, broker, financial intermediary, or investment adviser
* Acts solely as a technical and operational executor within the constraints of approved protocol parameters and contract code

In practice, the Servicer may assist with:

* Deployment and configuration of Credit Lines
* Partial or full repayment of Credit Lines using Reserves
* Withdrawal of unallocated Digital Assets to the relevant Wallet

All Servicer actions are executed on-chain and are publicly visible.

***

### Liquidation

Liquidation may be triggered where either of the following conditions is met:

* The Collateral Ratio of a Credit Line falls below the applicable minimum threshold; or
* A Credit Line is not fully repaid by its Due Date

Where either condition is met, the smart contract architecture authorises the Servicer to commence liquidation of Collateral and available Reserves.

**The liquidation process follows predefined protocol parameters:**

1. A grace period of 48 hours may be granted to the Borrower to remedy the situation before liquidation proceeds
2. If the grace period expires without remedy, the Servicer will liquidate Collateral and Reserves in a timely manner, prioritising decentralised exchange aggregators
3. Proceeds are distributed on a pro rata basis to Vault Depositors whose Digital Assets were allocated to the affected Credit Lines

The Servicer acts as a technical executor throughout this process. The Servicer does not exercise discretion over liquidation outcomes and does not mediate between parties.

Liquidation mechanics, grace period parameters, and applicable thresholds are defined by smart contract logic and are displayed on the Interface.

> **Important:** Even in fully collateralised situations, a Borrower may lose Digital Assets due to liquidation costs, collateral price movement during the liquidation period, or other factors. See the Terms of Use for full risk disclosures.


# Glossary

The following definitions apply across Credit Coop Protocol V2 documentation and correspond to defined terms in the Terms of Use. Any terms used in the Terms of Use but not defined there take the meaning set out below.

***

**Collateral** Digital Assets deposited by a Borrower to secure a Credit Line, as further defined in any applicable Loan and Security Agreement. Collateral is held in a smart contract and is subject to liquidation if the Collateral Ratio falls below the applicable minimum threshold.

***

**Collateral Ratio** The ratio of the value of Collateral deposited to the outstanding amount of a Credit Line, as determined by the relevant smart contract using on-chain price oracles. Borrowers must maintain the Collateral Ratio above the applicable minimum threshold at all times. Failure to do so may trigger liquidation.

***

**Credit Line** (also: Secured Line of Credit, Line of Credit) A revolving credit facility deployed and managed via smart contracts through the Credit Coop Protocol, accessible to Borrowers through the Interface. Credit Lines may be funded directly by individual Lenders or allocated from a Vault.

***

**Due Date** The date by which a Credit Line must be fully repaid, as specified in the relevant smart contract or Loan and Security Agreement. Failure to repay by the Due Date may trigger the liquidation process.

***

**Interface** The Credit Coop web-based interface and associated software tools provided by CMBT Labs to enable Users to interact with the Credit Coop Protocol. Available at [app.creditcoop.xyz](https://app.creditcoop.xyz). Also referred to as the "Services" in the Terms of Use.

***

**Lockbox Foundation** A Cayman Islands foundation company that stewards and operates the Credit Coop Protocol. Lockbox Foundation may act as lender of record under separate Loan and Security Agreements entered into directly with Borrowers. Lockbox Foundation is not a party to the Terms of Use and does not operate the Interface.

***

**Protocol** (also: Credit Coop Protocol) The Credit Coop decentralised smart contract protocol, comprising the Vault, Line, Spigot, and associated smart contracts deployed on public blockchain networks. The Protocol is stewarded and operated by Lockbox Foundation.

***

**Reserves** Digital Assets held in a Borrower's reserve smart contract position following transfer from Revenue Contracts. Reserves may be applied to repay Credit Lines or, where not required for repayment, withdrawn to the Borrower's Wallet.

***

**Revenue Contracts** Smart contracts or wallet addresses designated by a Borrower to receive receivables or other cash flows, and configured as a repayment source in conjunction with the Spigot smart contract.

***

**Servicer** The party designated by Lockbox Foundation to execute smart contract interactions and operational functions within the Credit Coop Protocol in accordance with approved protocol parameters. CMBT Labs may act as Servicer in its technical and operational capacity as DevCo for the Protocol. The Servicer role is modular and may be performed by one or more parties.

***

**Services** The software interface, non-custodial tooling, and associated access layer provided by CMBT Labs to enable Users to interact with the Credit Coop Protocol, as described in the Terms of Use.

***

**Vault** A pooled smart contract structure that accepts stablecoin deposits and allocates capital to Credit Lines and sources of liquid asset yield within the Protocol. Vaults are managed by Vault Curators. Vault Depositors receive Vault Tokens representing their pro rata participation.

***

**Vault Token** A blockchain-based token representing a Vault Depositor's pro rata participation in a Vault, redeemable for the underlying stablecoin subject to available liquidity. Vault Tokens are issued automatically upon deposit.


# Introduction

Developers ought to find enough info here and in the Product doc to evaluate the contracts (as a Borrower or a Lender) or to integrate them into your own protocol.

All the key initiatives concerning the codebase are available on our Github.&#x20;

Credit Coops's contracts are deployed saveral networks, including Ethereum, Polygon, Arbitrum and (soon to be) Plume.


# Deployed Contracts

Please reach out to your Credit Cooperative representative for access.&#x20;


# V1 Developer Material


# Architecture (v1)

Shows the main smart contracts that enable Secured Lines of Credit, their major functions and the interactions between the contracts.

<figure><img src="/files/kWmLujfZxNZMTfxOL8DV" alt=""><figcaption></figcaption></figure>

In v1 the Servicer acts through the blockchain address of the Arbiter role, an address used in the protocol for some critical system features.


# Functions and Methods

Core functions and methods of the Credit Coop smart contracts

What follows is a breakdown of external functions and methods contract by contract.

Please see [Secured Line Function Guide](https://www.notion.so/creditcoop/ce0f6e7d445f4538a5f02ec26648021d?v=67b7eb9d9e9b4e5ab69e6fd4ed22be75\&pvs=4) for a complete list of external functions in one table.


# LineOfCredit.sol

Core functions and methods of LineOfCredit.sol

LineOfCredit.sol is the core contract responsible for:

* Recording credit lines, positions and accounting for Borrowers and Lenders
* Defining Line of Credit terms (Oracle, Arbiter, Borrower, loan duration, interest rate, escrow and spigot collateral)
* Coordinating the Escrow, Spigot, and InterestRateCredit modules
* External calls to Oracle.sol and InterestRateCredit.sol
* Libraries - LineLib.sol, CreditLib.sol, CreditListLib.sol

<details>

<summary>External functions</summary>

```solidity
function init() external virtual returns(LineLib.STATUS)
function addCredit(uint128 drate,uint128 frate,uint256 amount,address token,address lender) external payable override nonReentrant whileActive mutualConsent(lender, borrower) returns (bytes32)
function borrow(bytes32 id, uint256 amount) external override nonReentrant whileActive onlyBorrower returns (bool)
function accrueInterest() external override returns(bool)
function counts() external view returns (uint256, uint256)
function healthcheck() external returns (LineLib.STATUS)
function increaseCredit(bytes32 id, uint256 amount) external payable override nonReentrant whileActive mutualConsentById(id)returns (bool) 
function setRates(bytes32 id,uint128 drate,uint128 frate) external override mutualConsentById(id) returns (bool)
function updateOutstandingDebt() external override returns (uint256, uint256)
function withdraw(bytes32 id, uint256 amount) external override nonReentrant returns (bool)
function depositAndRepay(uint256 amount )external payable override nonReentrant whileBorrowing returns (bool)
function declareInsolvent() external returns (bool)
function depositAndClose() external payable override nonReentrant whileBorrowing onlyBorrower returns (bool)
function close(bytes32 id) external payable override nonReentrant onlyBorrower returns (bool)
```

</details>

<details>

<summary>Methods</summary>

`function init()`: tests that any collateral facility is set up as expected, pointing to the correct address for the Line of Credit. If so, status changes to 'active'.

`function addCredit()`: a Lender deposits for the first time to an active Line of Credit

`function borrow(`): a Borrower draws down from an available credit position

`function accrueInterest()`: updates the amount of Interest Accrued that the Borrower owes

`function counts(`): returns the number of active credit positions within a Line of Credit and the number of credit positions irrespective of status

`function healthcheck()`: returns the status of the Line of Credit

`function increaseCredit()`: an existing Lender deposits additional capital

`function setRates()`: updates the Drawn Rate and the Facility Rate for a credit position

`function updateOutstandingDebt()`: returns total Borrower debt across all Lenders

`function withdraw()`: a Lender withdraws principal and accrued interest

`function depositAndRepay():` anyone can deposit funds to repay a Lender

`function declareInsolvent()`: Arbiter signifies that a Borrower is incapable of repaying debt permanently (used for secured lending)

`function depositAndClose()`: Borrower deposits enough Credit Tokens to repay and close a credit position

`function close()`: deletes a credit position that has already been fully repaid

</details>


# Oracle.sol

The Line of Credit makes external calls to the Oracle contract which acts as a wrapper contract to simplify integration with the Chainlink FeedRegistry

* Returns all token prices in USD 8-decimal denomination
* External calls to - Chainlink FeedRegistry
* Libraries - Chainlink Denominations

```solidity
function getLatestAnswer(address token) external returns (int256)
```

`getLatestAnswer()`: returns the current price for a token asset in USD (8 decimals)


# Spigot.sol

Core functions and methods of Spigot.sol

* Takes control of an onchain smart contract to escrow revenue earned by it
* Allows the Spigot Owner to claim escrowed funds at anytime
* Allows revenue splits between Spigot Owner and Operator
* Allows updating stakeholder addresses
* External calls to arbitrary contract with arbitrary calls
* Libraries - SpigotLib.sol, LineLib.sol

<details>

<summary>External Functions</summary>

```solidity
function addSpigot(address revenueContract, Setting memory setting) external returns (bool)
function updateWhitelistedFunction(bytes4 func, bool allowed) external returns (bool)
function claimRevenue(address revenueContract, bytes calldata data)external nonReentrantreturns (uint256 claimed)
function claimOwnerTokens(address token) external nonReentrant returns (uint256 claimed)
function claimOperatorTokens(address token) external nonReentrant returns (uint256 claimed)
function getOwnerTokens(address token) external view returns (uint256)
function getOperatorTokens(address token) external view returns (uint256)
function isWhitelisted(bytes4 func) external view returns(bool)
function getSetting(address revenueContract)external view returns(address, uint8, bytes4, bytes4)
function operate(address revenueContract, bytes calldata data) external returns (bool)
function updateOwnerSplit(address revenueContract, uint8 ownerSplit)external returns(bool)
function updateOwner(address newOwner) external returns (bool)
function updateOperator(address newOperator) external returns (bool)
function removeSpigot(address revenueContract)external whileNoUnclaimedRevenue(settings[revenueContract].token)returns (bool)
function owner() external view returns (address)
function operator() external view returns (address)
```

</details>

#### Spigot Methods

Many of the Spigot's functions are called by SpigotedLine.sol so read this in conjunction with methods for that contract, the Glossary and further product information herein.

| Function                      | Spigot Method                                                                                                                                                                                                                            | Deployment example SpigotedLine                                                                                                                                                                                                    |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `addSpigot()`                 | Attach a new Revenue Contract to a Spigot                                                                                                                                                                                                | The Spigot is deployed automatically when a Line is first deployed. addSpigot() is later used to add additional Revenue Contracts.                                                                                                 |
| `updateWhitelistedFunction()` | Allows the Owner to tell the Spigot to whitelist functions that the Operator is allowed to perform on its Revenue Contracts so that the Operator can still use those contracts whilst they are providing Revenue Tokens to repay credit. | <p>Called by updateWhitelist() in SpigotedLine which is only callable by the Arbiter (acting on behalf of Line/Lenders).<br><br>It updates what functions a Borrower (Operator) is allowed to perform on the Revenue Contract.</p> |
| `claimRevenue()`              | Claims Revenue Tokens into the Spigot escrow.                                                                                                                                                                                            | Claims Revenue Tokens and makes them available for later withdrawal to repay debt.                                                                                                                                                 |
| `claimOwnerTokens()`          | Owner withdraws its split of the Revenue Tokens that have already been claimed via claimRevenue().                                                                                                                                       | Allows a Lender to withdraw escrowed Revenue Tokens for the purposes of repaying debt.                                                                                                                                             |
| `claimOperatorTokens()`       | Operator withdraws its split of the Revenue Tokens that have already been claimed via claimRevenue().                                                                                                                                    | Allows a Borrower to withdraw any Revenue Tokens which weren't escrowed for Lenders.                                                                                                                                               |
| `getOwnerTokens()`            | Returns the amount of Revenue Tokens in escrow for the Owner ready to be withdrawn.                                                                                                                                                      |                                                                                                                                                                                                                                    |
| `getOperatorTokens()`         | Returns the amount of Revenue Tokens held for the Operator ready to be withdrawn.                                                                                                                                                        |                                                                                                                                                                                                                                    |
| `isWhitelisted()`             | Returns the list of whitelisted functions that an Operator is allowed to perform on a Revenue Contract whilst the Spigot is attached.                                                                                                    | Returns what the Borrower can do with a Revenue Contract whilst the Spigot is attached.                                                                                                                                            |
| `getSetting()`                | Returns the Spigot's settings for a Revenue Contract related to ownerSplit, claimFunction and transferOwnerFunction.                                                                                                                     | Returns important settings related to the setup of a Spigot to support a Secured Line. Particularly important for security.                                                                                                        |
| `operate()`                   | Allows an Operator to call the whitelisted functions on its Revenue Contracts attached to the Spigot and carry on its business as usual activities.                                                                                      | Allows the Borrower to operate as usual but with some constraints in order to protect the rights of Lenders.                                                                                                                       |
| `updateOwnerSplit()`          | Changes the revenue split between the Operator and the Owner based upon programmed conditions or otherwise if the Owner and Operator wish to change the split.                                                                           | Changes the revenue split between a Borrower and Lenders based upon the status of the Line or other conditions.                                                                                                                    |
| `updateOwner()`               | Puts a new Owner in control the Spigot.                                                                                                                                                                                                  | In practice this would either change the Owner to the Borrower (Line fully repaid) or to the Arbiter (Line impaired)                                                                                                               |
| `updateOperator()`            | Puts a new Operator address in place to interact with the Revenue Contracts if ever this were needed.                                                                                                                                    | <p>This function exists for convenience/maintenance purposes only right now.</p><p>A Borrower may want to change an address for managing its protocol. Allowing key rotation is good opsec.</p>                                    |
| `removeSpigot()`              | Removes control over a ***single*** Revenue Contract.                                                                                                                                                                                    | Used for example by a Borrower (acting as Spigot Owner) to fully remove the Spigot from a ***single*** Revenue Contract after some debt that was secured by that Revenue Contract has been repaid.                                 |
| `owner()`                     | Returns the address of the current Spigot Owner.                                                                                                                                                                                         |                                                                                                                                                                                                                                    |
| `operator()`                  | Returns the address of the current Spigot Operator.                                                                                                                                                                                      |                                                                                                                                                                                                                                    |


# SpigotedLine.sol

Core functions and methods of SpigotedLine.sol

* An integration between [Spigot.sol](/developer-material/v1-developer-material/functions-and-methods/spigot.sol) and [LineOfCredit.sol](/developer-material/v1-developer-material/functions-and-methods/lineofcredit.sol).
* It owns the Spigot so it's important that it can properly manage and call Spigot.sol and doesn't lose ownership unless `releaseSpigot()` successfully executes.
* Manages a Spigot's configuration based on the health status of a Line of Credit
* Trades Revenue Tokens for Credit Tokens owed to lenders using 0x protocol
* Stores excess revenue or trade slippage in `unused` tokens for later use in repayment
* Allows Borrowers to clawback escrowed tokens if a Line is fully repaid
* Allows liquidating `unused` or the Spigot itself if a Line's status is LIQUIDATABLE
* External calls to - 0x protocol,[ Spigot.sol](/developer-material/v1-developer-material/functions-and-methods/spigot.sol)
* Libraries -[ LineLib.sol](https://github.com/BobZedF/Gitbooktest/blob/main/developers/functions-and-methods/broken-reference/README.md), SpigotedLineLib.sol

<details>

<summary>External Functions</summary>

```solidity
function claimAndRepay(address claimToken, bytes calldata zeroExTradeData)external whileBorrowing nonReentrant returns (uint256)function claimAndTrade(address claimToken, bytes calldata zeroExTradeData)external whileBorrowing nonReentrant returns (uint256)
function unused(address token) external view returns (uint256)
function useAndRepay(uint256 amount) external whileBorrowing returns(bool)
function updateWhitelist(bytes4 func, bool allowed)external returns (bool)
function releaseSpigot(address to) external returns (bool)
function sweep(address to, address token) external nonReentrant returns (uint256)
```

</details>

#### SpigotedLine Methods

Many of the features of the Spigoted Line of Credit product depend on and call Spigot.sol. Read this in conjunction with methods for that contract, the Glossary and further product information herein.

| Function            | SpigotedLine Method                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `claimAndRepay()`   | <p>Claims Revenue Tokens from the Spigot, trades them for Credit Tokens via a Dex and makes the Credit Tokens available to Lender withdraw.<br></p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `claimAndTrade()`   | <p>Claims Revenue Tokens from the Spigot and trades them for Credit Tokens via a Dex.<br><br>The newly exchanged Credit Tokens are held in 'unusedTokens' ready for a Lender to using useAndRepay() and withdraw().<br><br>This feature allows a Borrower to take advantage of an increase in the relative value of the Revenue Token compared to the Credit Token and to in effect use less Revenue Tokens to repay the same amount of debt.<br></p><p>The system ensures that the first Credit Token in the repayment queue is the one being bought.<br><br>A Line can have multiple Credit Tokens being lent out/borrowed and multiple Revenue Tokens being escrowed to repay the debt.<br></p> |
| `unused()`          | <p>Returns the amount of Credit Tokens that have been bought with Revenue Tokens from the Spigot and which haven't yet been withdrawn by a Lender or otherwise used by the Borrower to repay.<br></p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `useAndRepay()`     | <p>Allows a Lender or a Borrower to use Credit Tokens (that have already been claimed/traded) from 'unusedTokens' in order to repay debt.<br></p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `updateWhitelist()` | <p>Sets or updates the whitelisted functions that a Borrower \[as Operator] is allowed to perform on its Revenue Contracts so that it can still use those contracts whilst providing Revenue Tokens to repay credit. Only callable by an Arbiter.<br></p>                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `releaseSpigot()`   | <p>Transfers ownership of the entire Spigot from the Line of Credit to either the Borrower (if a Line of Credit has been been fully repaid) or to the Arbiter (if the Line of Credit is liquidatable).<br></p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `sweep()`           | <p>After a loan has been repaid, sends any remaining Revenue Tokens or Credit Tokens to the Borrower.<br><br>In case of a Borrower default however (loan status = liquidatable), this function serves as a liquidation mechanism that is called in an effort to increase the Lenders' recovery rate and reduce the "loss given default (LGD)"</p><p><br></p>                                                                                                                                                                                                                                                                                                                                       |

\`\`


# Escrow\.sol

Core functions and methods of Escrow\.sol

* Allows a Borrower to deposit tokens as collateral for a Line of Credit
* Allows a Borrower to withdraw collateral so long as it doesn't cause the status of a Line to be LIQUIDATABLE
* Allows Arbiter to whitelist (enable) specific collateral allowed for a Line
* Allows Arbiter to liquidate collateral if the status is LIQUIDATABLE
* External calls to - Oracle.sol, LineOfCredit.sol
* Libraries - LineLib.sol, CreditLib.sol, EscrowLib.sol

<details>

<summary>External Functions</summary>

```solidity
function enableCollateral(address token) external returns (bool)
function addCollateral(uint256 amount, address token) external payable nonReentrant returns (uint256)
function getCollateralRatio() external returns (uint256)
function getCollateralValue() external returns (uint256)
function releaseCollateral(uint256 amount, address token, address to) external nonReentrant returns (uint256)
function liquidate(uint256 amount, address token, address to) external nonReentrant returns (bool)
function updateLine(address _line) external returns(bool)
function line() external view override returns(address)
function isLiquidatable() external returns(bool)
```

</details>

<details>

<summary>Methods</summary>

`function enableCollateral():` Allows an Arbiter to whitelist an ERC-20 token or ERC-4626 vault to be used as collateral

`function addCollateral():` Allows a Borrower to adds whitelisted (enabled) tokens as collateral after which the app updates the collateral ratio

`function getCollateralRatio():` Returns the ratio of the value of collateral to outstanding debt

`function getCollateralValue():` Returns the latest value of the collateral deposited by a Borrower (in USD)

`function releaseCollateral():` Allows a Borrower to withdraw any amount of collateral as long as the minimum collateral ratio is maintained.

`function liquidate():` Allows the Arbiter to liquidate collateral

`function updateLine():` Allows a Borrower to transfer (roll over) collateral to a new Line of Credit.

`function line():` Returns the address of the the current controller of the Escrow contract

`function isLiquidatable():` Returns true if the collateral ratio is lower than minimum collateral ratio

</details>


# EscrowedLine.sol

EscrowedLine.sol is an abstract contract holding all the token collateral of a Borrower. It doesn't contain any external functions.

* Allows an Arbiter to liquidate collateral if the Line of Credit's status is LIQUIDATABLE
* Updates a Line's status based on the latest collateral ratio vs minimum collateral ratio (as calculated in Escrow\.sol)
* External calls to - Escrow\.sol
* Libraries - LineLib.sol


# SecuredLine.sol

Core functions and methods of SecuredLine.sol

* Combines both collateral modules (SpigotedLine.sol + EscrowedLine.sol) with the core lending functionality from LineOfCredit.sol
* Create a fully Secured Lending Solution backed by Revenue Tokens via Spigot.sol and/or token collateral via Escrow\.sol.
* Allows transferring token collateral and Spigots to new Lines of Credit
* External calls to - Oracle.sol, InterestRateCredit.sol, EscrowedLine.sol, Spigot.sol, 0x protocol
* Libraries - LineLib.sol, SpigotedLineLib.sol

<details>

<summary>External Functions</summary>

```solidity
function rollover(address newLine)external override onlyBorrower returns(bool)
function liquidate(uint256 amount,address targetToken) external returns(uint256)
```

</details>

<details>

<summary>Methods</summary>

`function rollover():` Allows a Borrower to transfer escrowed token collateral and Spigots to a new Line of Credit

`function liquidate():` Allows the Arbiter to liquidate collateral

</details>


# LineFactory.sol

Core functions and methods of LineFactory.sol

Factory contract to automate the deployment and re-usage of Lines of Credit and related Spigot and Escrow features

<details>

<summary>External functions</summary>

```solidity
function deploySecuredLine(address borrower, uint256 ttl) external returns (address line)
function deploySecuredLineWithConfig(CoreLineParams calldata coreParams) external returns (address line
function deploySecuredLineWithModules(CoreLineParams calldata coreParams, address mSpigot, address mEscrow) external returns (address line)
function rolloverSecuredLine(address payable oldLine, address borrower, uint256 ttl) external returns (address line)
function deploySpigot(address owner, address operator) external returns (address)
function deployEscrow(uint32 minCRatio, address owner, address borrower) external returns (address)
```

</details>

<details>

<summary>Methods</summary>

`function deploySecuredLine():` Deploys a Secured Line including a Spigot and a collateral escrow with default settings

`function deploySecuredLineWithConfig():` Deploys a Secured Line including a Spigot and a collateral escrow configured according to Borrower and Lender agreed terms

`function deploySecuredLineWithModules():` Deploys a new Secured Line and transfers ownership to that new Line of an existing Escrowed Token Collateral and Spigot

`function rolloverSecuredLine():` Allows a Borrower to set up a new Line based upon the terms of a currently active or repaid Line (or any other status)

`function deploySpigot():` Deploys a Spigot with default settings

`function deployEscrow():` Deploys a collateral escrow with default settings

</details>


# Libraries

#### **LineLib.sol**

Stores basic functions for the Line of Credit e.g. health statuses and transferring tokens

#### **CreditLib.sol**

Stores basic functions for interacting with Lender positions e.g. computing ids for individual credit lines, accruing interest and repaying debt

#### **CreditListLib.sol**

Stores functionality for interacting with collections of Lender positions on a Line e.g. adding and removing positions or re-sorting positions in the repayment queue

#### SpigotLib.sol

Stores functionality for claiming revenue, updating revenue splits, updating stakeholder addresses and all other Spigot functions

#### SpigotedLineLib.sol

Stores functionality related to a Line which is secured by a Spigot

#### EscrowLib.sol

* Calculates the total value of collateral assets escrowed
* Calculates collateral ratio based on collateral value
* Ensures that whitelisted (enabled) collateral enabled has a price feed

#### LineFactoryLib.sol

Stores functionality related to deploying multiple contracts simultaneously

#### MutualConsent.sol

* Forked from <https://github.com/IndexCoop/index-coop-smart-contracts/blob/1acec44229b3aaf4a40dad2095b0cc6accb8fbfc/contracts/lib/MutualUpgrade.sol>
* Essentially a 2/2 multisig baked into your contract
* Ensures that two predefined addresses both sign a transaction with the same inputs and then executes the function with those parameters.

#### Chainlink Denominations


# InterestRateCredit.sol

The Line of Credit makes external calls to the setRate() function of Interest Rate Credit contract

This contract stores interest rates and the last time interest was accrued for individual credit positions on a Line of Credit.

* It only calculates interest owed. LineOfCredit.sol is responsible for updating balances
* Only allows LineOfCredit.sol to call it
* It only has one external function, setRate() as mentioned below.

```solidity
function setRate(bytes32 id,uint128 dRate,uint128 fRate) external onlyLineContract returns (bool)
```

`setRate()`: update the interest rates for a credit position (after being called by LineOfCredit.sol)


# Accrued Interest Calculation

Describes how accrued interest is calculated and where and when this happens

### Formulae

<details>

<summary><strong>Interest = (r * x * t) / 1yr / 10000</strong></summary>

r = APR in basis points (e.g. 5% = 500bp)

x = amount of tokens

t = time (in seconds)

1 year = 365.25 days (in seconds)

</details>

<details>

<summary>Full Accrued Interest formula</summary>

`InterestAccrued =`

`(rate.dRate * drawnBalance * timespan) / INTEREST_DENOMINATOR`

`+`

`(rate.fRate * (facilityBalance - drawnBalance) * timespan) / INTEREST_DENOMINATOR`

</details>

### Parameters

<details>

<summary>interestAccrued</summary>

Interest owed by a Borrower but not yet repaid to the Line of Credit contract

</details>

<details>

<summary>Interest denominator = 365.25 days * Base denominator</summary>

</details>

<details>

<summary>Base denominator</summary>

10000 (adjustment factor since rates are expressed in basis points (bps) --> e.g. 5% rate is expressed as 500bp so we need to divide by 100 to get a % and then by another 100 to arrive at the decimal (500/100/100 = 0.05)

</details>

<details>

<summary>One year</summary>

One Julian astronomical year, has 365.25 days: 1 year = 365.25 days = (365.25 days) × (24 hours/day) × (3600 seconds/hour) = 31557600 seconds

</details>

<details>

<summary>dRate</summary>

The annual interest rate charged to a Borrower on borrowed / drawn down funds (in basis points to 4 decimals, e.g. 1000bp = 10% and 1234bp = 12.34% and 1234.56bp = 12.3456%)

</details>

<details>

<summary>drawnBalance</summary>

The balance of funds that a Borrower has drawn down on the Line of Credit

</details>

<details>

<summary>fRate</summary>

The annual interest rate charged to a Borrower on the remaining funds available, but not yet drawn down aka rate charged on the available facility headroom(in basis points to 4 decimals).

</details>

<details>

<summary>facilityBalance</summary>

The remaining balance of funds that a Borrower can still drawn down on the Line of Credit (aka headroom)

</details>

<details>

<summary>timespan= block.timestamp - rate.lastAccrued</summary>

The number of seconds for which interest will be accrued

</details>

<details>

<summary>block.timestamp</summary>

The block timestamp for the block during which interest is calculated, in seconds

</details>

### Contract workflow

Please see [here](/developer-material/v1-developer-material/functions-and-methods/interestratecredit.sol/interest-accrued-contract-flow) for an overview of the contract and function workflow.

The definitions below are useful for that.

<details>

<summary>Principal</summary>

The amount of a Lender's Deposit that has actually been drawn down by the Borrower (USD)

</details>

<details>

<summary>Deposit</summary>

The sum of the total liquidity provided by a Lender in a given token on a Line of Credit

</details>

<details>

<summary>id</summary>

Reference id for the Credit Position made available to a Borrower by a single Lender for a given token on a Line

</details>


# 'Interest Accrued' contract flow

Overviews the contract workflow for how and when InterestAccrued is updated

{% hint style="info" %}
Prior advised reading and definitions: '[finance view](/developer-material/v1-developer-material/functions-and-methods/interestratecredit.sol/accrued-interest-calculation)' of how accrued interest is calculated in our contracts.

The term 'InterestAccrued' is the Interest owed by a Borrower but not yet repaid to the Line of Credit contract and made available for withdrawal by a Lender.
{% endhint %}

Steps 2 - 5 below deal with calculating calculating accrued interest in order to update`InterestAccrued`for a single credit position id as either a direct result of the external function request (step 1) or indirectly as a result of another action such as a change in the balance on a credit line id.

Step 1 is an external function that updates the accrued interest for **all** credit position ids in a Line of Credit facility

<details>

<summary>1) <code>accrueInterest()</code> in LineOfCredit.sol</summary>

This external function *loops over all credit position ids* and calls related internal functions during which InterestRateCredit.sol is called with the id data and then i`nterestAccrued` is updated.

```solidity
 function accrueInterest() external override returns(bool) {
        uint256 len = ids.length;
        bytes32 id;
        for (uint256 i; i < len; ++i) {
          id = ids[i];
          Credit memory credit = credits[id];
          credits[id] = _accrue(credit, id);
          
        }
        
        return true;
    }
```

</details>

<details>

<summary>2) <code>_accrue</code> in LineOfCredit.sol</summary>

This internal function runs within step 1 or otherwise at any time the balance on a credit line changes or the interest rates are changed by mutual consent between a Borrower and a Lender.

```solidity
    function _accrue(Credit memory credit, bytes32 id) internal returns (Credit memory) {
        if (!credit.isOpen) {
            return credit;
        }
        return CreditLib.accrue(credit, id, address(interestRate));
    }
```

</details>

<details>

<summary>3) <code>accrue()</code> in CreditLib.sol</summary>

Called by `_accrue()` in step 2 above any time the balance on a credit position changes or the interest rates are changed by mutual consent between a Borrower and a Lender.

It returns an updated token denominated `interestAccrued` for a single id.

It does so by adding the new amount of interest to accrue to the prior amount of `interestAccrued` recorded.

This new amount of interest to accrue is called `accruedToken` and is calculated in InterestRateCredit.sol (see steps 4 and 5 below).

```solidity
function accrue(
        ILineOfCredit.Credit memory credit,
        bytes32 id,
        address interest
    ) public returns (ILineOfCredit.Credit memory) {
        unchecked {
            // interest will almost always be less than deposit
            // low risk of overflow unless extremely high interest rate

            // get token demoninated interest accrued
            uint256 accruedToken = IInterestRateCredit(interest).accrueInterest(id, credit.principal, credit.deposit);

            // update credit line balance
            credit.interestAccrued += accruedToken;

            emit InterestAccrued(id, accruedToken);
            return credit;
        }
    }
}
```

</details>

<details>

<summary>4) <code>accrueInterest()</code> in InterestRateCredit.sol</summary>

This is the main function for calculating the amount by which `interestAccrued` should be updated for *a single credit position id*, callable indirectly by `_accrue()` in LineOfCredit.sol (step 2 above) and then subsequently directly by `accrue()` in CreditLib.sol (step 3)

```solidity
function accrueInterest(
        bytes32 id,
        uint256 drawnBalance,
        uint256 facilityBalance
    ) external override onlyLineContract returns (uint256) {
        return _accrueInterest(id, drawnBalance, facilityBalance);
    }
```

</details>

<details>

<summary>5) <code>_accrueInterest() and _calculateInterestOwed</code> in InterestRateCredit.sol</summary>

Finally, this is where the amount by which `interestAccrued should be updated` is calculated per credit position id.

[For a detailed explanation of the formula, please see here.](/developer-material/v1-developer-material/functions-and-methods/interestratecredit.sol/accrued-interest-calculation)

```solidity
 function _accrueInterest(bytes32 id, uint256 drawnBalance, uint256 facilityBalance) internal returns (uint256) {
        Rate memory rate = rates[id];
        uint256 timespan = block.timestamp - rate.lastAccrued;
        // update last timestamp in storage
        rates[id].lastAccrued = block.timestamp;

        return (_calculateInterestOwed(rate.dRate, drawnBalance, timespan) +
            _calculateInterestOwed(rate.fRate, (facilityBalance - drawnBalance), timespan));
    }
 
 function _calculateInterestOwed(
        uint256 bpsRate,
        uint256 balance,
        uint256 timespan
   ) internal pure returns (uint256) {
        return (bpsRate * balance * timespan) / INTEREST_DENOMINATOR;
   }
```

</details>

*last updated Dec 29 2022*


# Advanced Jargon

Here we will add terms on an ongoing basis that need explaining for product managers and developers in more precise details than in our simplified [Glossary](https://creditcoop.notion.site/998a21dc55434a8cab2d280496e211fd?v=68edb6ba161b4c5882a65391e2be6665).&#x20;

Spigot related terms are defined in the context of their usage in a Secured Line of Credit.

<table><thead><tr><th width="204.5">Term</th><th>Meaning</th></tr></thead><tbody><tr><td>Available</td><td><p>The amount of funds available to a Borrower to draw down on a given credit position, made up of:<br></p><p>funds deposited by lenders (aka deposit)</p><p>-<br>funds drawn down by the Borrower (aka principal)</p><p>+</p><p>interest repaid by a Borrower to the Line of Credit contract but not yet withdrawn by Lenders (aka interestRepaid)</p></td></tr><tr><td>id</td><td>Reference id for the credit position made available to a Borrower by a single Lender for a given token on a Line of Credit. If a Lender deposits a second, different token into the same Line of Credit then this is treated as a separate credit position and id.</td></tr><tr><td>Interest Repaid</td><td>Interest repaid by a Borrower to the Line of Credit contract but not yet withdrawn by a Lender</td></tr><tr><td>Last Accrued</td><td>The time stamp at which accrued interest was last calculated on a credit line (id) and added to the total amount of Interest Accrued (accrued interest owed but not yet repaid).</td></tr><tr><td>Mutual consent</td><td>A process whereby certain things can only happen if two out of two parties sign off (e.g. a Lender depositing into a Line of Credit)</td></tr><tr><td>Next in Q</td><td>The ID of the next lender deposit / credit position to be repaid by the Borrower according to the order in which deposits were drawn down (FIFO).<br><br>If nothing has been drawn down then priority is according to the order in which withdraw has been initiated.</td></tr><tr><td>Operator (Spigot Operator)</td><td>The Spigot Operator is an address through which an obliging party in an agreement (e.g. a Borrower) is still able to execute whitelisted functions to carry on business as usual related to a Revenue Contract controlled by the Spigot Owner for the benefit of one or more Lenders.<br><br>It's also the address which receives all remaining Revenue Tokens that are not escrowed in the Spigot for the benefit of the Lenders to repay debt.</td></tr><tr><td>Owner (Spigot Owner)</td><td><p>The Spigot Owner manages a Spigot for the benefit of one or more Lenders based upon programmable events.<br></p><p>In practice, the Owner can be (i) Borrower in order to deploy the Line of Credit, then (ii) the Line itself (representing Lender(s)) and governing the overall agreement) and also (iii) an Arbiter if the Line status becomes liquidatable.<br></p><p>Ownership is transferred during the lifetime of a Line of Credit according to programmed rules.</p></td></tr><tr><td>Owner Tokens</td><td>The amount of Revenue Tokens claimed from one or more Revenue Contracts into the Spigot escrow and which are currently available for withdrawal by a Lender.</td></tr><tr><td>Principal</td><td>The amount of a Lender's Deposit that has actually been drawn down by the Borrower.</td></tr><tr><td>Uninitialized</td><td>The status of the the Line when it’s been deployed but some checks haven’t yet been passed, such as checking that the Line is the owner of the escrow, i.e. line.init() hasn’t been called on the line.</td></tr><tr><td>Unused Tokens</td><td>Credit Tokens that have been purchased with Revenue Tokens after a claim from the Spigot. These Credit Tokens are available to be withdrawn by a Lender.</td></tr><tr><td></td><td></td></tr></tbody></table>


# Repaying Debt - Function View

Illustrates the full scope of options for paying down debt on an active Line of Credit.

<figure><img src="/files/9XI7MYwkcT6t7YJwtfyM" alt=""><figcaption></figcaption></figure>


# Valuation Oracle

The Oracle is responsible for valuing all the assets of a Line of Credit. This includes tokens held in the Escrow contract as collateral, Credit Tokens deposited by a Lender and any interest accrued. If a token is not supported by the Oracle, any transaction by a Lender to deposit that token will fail.

For every Line of Credit contract a decision is required at deployment as to which Oracle to use. The standard Oracle used is the [Chainlink Feed Registry](https://docs.chain.link/docs/feed-registry/). This allows automatic support for any asset available on the Chainlink oracle network which means that any token listed on the registry can be lent out / borrowed or used as collateral.

If desired for a given loan, you can deploy your own oracle that supports NFT pricing, off chain assets, etc.

Borrowers and Lenders are both responsible for reviewing the Oracle address on a Line and for ensuring that it's a reliable oracle to use. If an incorrect asset price is returned by the Oracle, either party can be negatively affected which is why we default to the battle tested, industry standard Chainlink oracles.


# Arbiter Role (v1)

In v1 the Servicer acts through the blockchain address of the Arbiter role, an address used in the protocol for some critical system features.

The Arbiter is a role in our contracts that works to ensure a fair treatment in our system.&#x20;

It can be a third-party trusted by the Borrower and the Lender or it can be a single Lender that can represent all Lenders vis-a-vis a Borrower.

In v1 the Arbiter's main role is to discourage and prevent bad behaviour by Borrowers and to ensure that Lenders are in the best position possible to be repaid.

It does so through having privileged access to certain functions, some of which are highlighted in the following sections.


# liquidate() and declareInsolvent()

### `liquidate()`

A bespoke approach is taken wish the aim to avoid automatic liquidations. We believe in a process for restructuring debt or in giving borrowers time to top up collateral or add additional revenue streams to the Spigot.

The Arbiter is responsible for initiating and executing liquidations.

This privileged function can only be executed when the loan status is liquidatable, triggered for example when the escrowed token collateral account becomes undercollateralized (relative to the collateral ratio set for the loan) or when a Borrower fails to repay before the deadline.

### `declareInsolvency()`

The Arbiter can declare that a Borrower is incapable of repaying debt any more than the current proceeds after liquidating the Borrower's collateral and/or claiming all of the Revenue Tokens in the Spigot.&#x20;


# Spigot related functions

The Arbiter role has privileged access rights to the following functions

### `addSpigot()`

The Arbiter can add a second or further Revenue Contracts to a Line of Credit that has already been deployed.

### `updateWhitelist()`

The Arbiter can allow the Borrower to call certain functions on their protocol contracts for maintenance.

### `releaseSpigot()`

Transfers ownership of the entire Spigot from the Line of Credit to the Arbiter if the Line of Credit is liquidatable.


# enableCollateral()

Only the Arbiter can whitelist Asset Collateral used in the escrow contract.

This will occur if a conventional approach is used to collateralize a Line of Credit, i.e. taking tokens deposited by a Borrower as collateral and using their spot price to calculate a collateral ratio.


# Edge Cases and Risk Situations

In this section, we explain some edge cases and risk situations, whether they are managed and covered automatically, and what the procedure is case by case.

Attack vectors mainly focus around the risk to Lenders' deposits, there are also risks to consider for Borrowers too.

<details>

<summary>Negative Impact of Whitelisted functions on the Spigot</summary>

*related to updateWhitelist(), updateWhitelistedFunction() and operate()*

**Attack Vector**

A bad actor could propose a whitelisted function that affects the normal functioning of the Spigot

**Background Information**

Whitelisted functions are those allowed to be performed on a Revenue contract so that the Operator (Borrower) can still use the contract whilst providing Revenue Tokens to repay debt.

**Mitigation Strategies**

Only whitelisted functions can be called by an Operator on the Revenue Contract.

operate() can only work on Revenue Contracts authorised by the Spigot Owner

The Spigot Owner has verified the function logic of the whitelisted function and ensured that they poses no risk to the Spigot’s functionality

</details>

<details>

<summary>Upgradeable Revenue Contract</summary>

**Attack Vector**

A Borrower could upgrade the Revenue Contract securing the Line of Credit.

They could change the underlying logic of the already whitelisted functions.

They could create new functions with the same function signatures.

Either of these can cause the Spigot to lose control of the underlying Revenue Contract(s) and to not be able to claim Revenue Tokens.

**Mitigation Strategies**

Spigot Owners should only consider immutable smart contracts as candidates to be Revenue Contracts

</details>

<details>

<summary>Attack on Revenue Contract</summary>

**Attack Vector**

A Spigot could be deployed that has been approved for transferring Revenue Tokens to a malicious contract

**Mitigation Strategies**

Although this is mitigated by only letting the Owner add Revenue Contracts to a Spigot it could still be susceptible to social engineering.

<img src="/files/L5MfvoIdkXYabQtduSeU" alt="" data-size="original">

</details>

<details>

<summary>Intentional Default by Borrower</summary>

**Attack Vector**

A Borrower could try to take out a loan partly secured by a Revenue Contract that they intend to deprecate or which they know won't make enough revenue to repay the loan with the agreed revenue split.

**Mitigation Strategies**

To ensure repayment to a Borrower’s full ability, the Spigot will automatically switch to escrowing 100% of Revenue Tokens if the loan is past due or if the spot value of any collateral becomes too low.

It is also theoretically possible to repossess a Borrower's entire protocol using contracts controlled by the Spigot and sell it off to an investment DAO or related protocol DAO to repay Lenders.

</details>

<details>

<summary>Malicious Spigot Owner</summary>

**Attack Vector**

A Spigot Owner could be configured to retain ownership of Revenue Contracts even though all debt has been repaid

**Mitigation Strategies**

Before giving control of a Revenue Contract to a Spigot, a Borrower should ensure that the Owner is a smart contract with the proper functions in place to later return ownership as and when appropriate.

The Owner should not be an EOA and if it is a smart contract that is not a Line of Credit contract then a Borrower should ensure it is verified on etherscan and has smart contract audits specifically related to those functions related to a Spigot integration.

</details>

<details>

<summary>Borrower Trading Revenue Tokens for a Fake Credit Token</summary>

**Attack Vector**

Borrower creates a fake credit token and creates an LP pool with the fake credit token and a second token in which they earn revenue in (use ETH for simplicity). Pool has really high ETH price so they don’t need a lot of ETH to initiate an attack.

When calling claimAndRepay(), they trade the Revenue Tokens (ETH) into the fake credit token that they created allowing them to capture the value instead of Lenders being repaid.

**Mitigation strategies**

The Credit Tokens into which Revenue Tokens are converted are selected automatically according to the first position in the repayment queue. This way the acquired Credit Tokens will always be those which a Lender has deposited.

0x (the DEX we’re using) generally doesn’t support illiquid and/or unknown tokens

0x only allows 1 <>1 token trading so it can’t trade a tiny amount of the Revenue tokens into Credit Token and the rest to the fake token. It must trade all Revenue tokens into Credit Tokens\
\
A further mitigation strategy implemented is limit access to the Arbiter for claimAndTrade() and claimAndRepay().

</details>

<details>

<summary>Abuse of Split of Revenue Tokens from a Spigot</summary>

*related to updateOwnerSplit()*

**Attack Vector**

In a Spigoted Line of Credit, the updateOwnerSplit() function could be abused by the Borrower or the Lender.

If the ownerSplit parameter is set below the defaultRevenueSplit parameter, the Lender could call it to increase the split percentage which would lead to more Revenue Tokens being used to pay off the debt more quickly.

If the ownerSplit parameter is set above the defaultRevenueSplit parameter, the Borrower could call it to decrease the split percentage. This would lead to less revenue being used to pay off the debt, and more revenue would return to the Borrower’s Treasury.

No authorization check is implemented for who can call this function.

**Mitigation Strategies**

Borrower and Lender have agreed to the defaultRevenueSplit terms so there's not really “abuse”

The terms are transparent and deterministic so can't really be exploited, just favorable for certain stakeholders in certain situations

It makes the default revenue split a schilling point for all revenue splits (we can customize per contract if we wanted to)

</details>

<details>

<summary>Borrower can still claim Revenue Tokens from a Spigot after failing to repay by the end of the term</summary>

*related to claimRevenue()*&#x20;

**Background Information**

If a Line of Credit hasn’t been fully repaid by the due date, the healthcheck () function must be called explicitly to set the status to liquidatable. The Arbiter can then act to ensure that 100% of Revenue Tokens are escrowed until the loan can be fully repaid.

**Attack Vector**

A loan’s liquidatable status is not automatically propagated to the Spigot if a Line hasn’t been fully repaid by its expiry date and healthcheck() has been run.

claimRevenue() function has no authorization implemented.

As a result, the borrower can front-run the Arbiter reset of the updateOwnerSplit() function with claimRevenue() to obtain one more revenue share from spigot.

**Mitigation Strategies**

All Borrowers and Lenders are incentivized to call claimRevenue() as frequently as gas allows because Borrows need cashflow and Lenders want to escrow as much collateral as possible.

Although the risk is not zero, we expect the surface area to be negligible compared to the size of the loans and interest payments.

</details>

<details>

<summary>Malicious Arbiter could transfer Spigot Ownership to a Borrower before a loan has been repaid</summary>

**Background Information**

When setting up a Secured Line of Credit, it’s assumed that a Borrower adds a Spigot with a Revenue Contract and transfers the ownership of that Spigot to the Line of Credit, acting as new Owner for the benefit of Lenders.

The Arbiter can call updateWhitelist() to allow or disallow execution of the transfer ownership function for the Operator (Borrower) for the Revenue Contract.

**Attack Vector**

A malicious Arbiter could whitelist the transfer ownership function for the Borrower.

The Borrower could then transfer the ownership from the Line back to itself using the \_operate() function.

The Borrower can already have drawn down funds before this attack, leaving Lenders with no recourse.

**Mitigation Strategies**

Whilst an Arbiter is supposed to be a 3rd party negotiator between all Lenders and a Borrower, based on its roles in a Line of Credit the Arbiter is more like an advocate or an agent for Lenders.

Lenders should select trusted arbiters as that is the only trusted part of our system currently but we plan on automating/decentralising them later.

</details>

<details>

<summary>Borrower can prevent Lender from withdrawing (and can minimize drawn interest accruing)</summary>

**Attack Vector**

When a Lender attempts to withdraw(), a Borrower could front-run it with the borrow() function, and immediately call the repay() function to repay what it had drawn down.

No drawn interest would be applied and all funds would still be available to borrow.

The borrower could repeat that until the end of the term at which point the Borrower wouldn't be able to borrow again or would be liquidated if they didn't fully repay

**Mitigation Strategies**

Whilst this is technically possible, a flashbot transaction sent by the Lender ought still be able to withdraw the funds

</details>

<details>

<summary>Enabling token collateral - internal transaction error</summary>

A Borrower can post any ERC-20 or ERC-4626 token as collateral, provided that the token has been whitelisted (enabled) by the Arbiter.

If however enableCollateral() is called for a token that is not ERC-4626 compliant then an internal transaction error will be returned (an example is provided below)

<img src="/files/jtdrkKspLczKp8P41eI1" alt="" data-size="original">

Whilst ERC-4626 tokens can be enabled, only the underlying collateral is used for pricing.

ERC-20 and ERC-4626 contracts must be verified for malicious code / exploits before enabling.\\

</details>

<details>

<summary>Lender can deposit after Line expiry</summary>

A Borrower can no longer draw down after a Line has expired.\
\
If however there are no outstanding drawdowns at expiry and therefore the Line is not in default, it's still possible for a Lender to deposit funds to the Line.\
\
This creates a 'technical default' which causes the Line to be liquidatable.

In this case, a Lender simply has to withdraw the deposited funds.

</details>

Archived Items

<details>

<summary>Bad Actor Claiming Revenue Tokens from a Spigot</summary>

*This risk has been fully mitigated.*&#x20;

*claimAndTrade() and claimAndRepay() can now only be called by the Arbiter*

*related to claimRevenue()*

**Attack Vector**

A Revenue Contract could be called by a bad actor via claimRevenue() with the intention of siphoning off Revenue Tokens.

**Background Information**

claimFunction is the function signature to call a Revenue Contract and claim Revenue Tokens

claimRevenue() claims Revenue Tokens and leaves them in escrow (i.e. unlike claimAndTrade() and claimAndRepay() it doesn’t convert Revenue Tokens to Credit Tokens to be made available for Lender withdrawal or actually repaid to Lenders respectively).

**Mitigation Strategies**

The contracts are written such that claimFunction is restricted to being only capable of calling a Revenue Contract with the sole purpose of escrowing Revenue Tokens.

claimRevenue() can only call the predetermined claimFunction as set by the Spigot Owner

claimFunction can’t be called in operate(), the Spigot function that allows a Borrower to call the whitelisted functions on its Revenue Contracts and carry on its business as usual activities.

The Borrower should verify that claimFunction does not modify any other state on the underlying Revenue Contract.<br>

</details>


# Security Audits

Please contact us for details of our audits.


# Credit Coop Platform v3 API

These are the API endpoints for the Credit Coop platform.


# Platform

General platform endpoints

## List supported blockchain networks

> List all supported blockchain networks

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Platform","description":"General platform endpoints"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]},{}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"Network":{"type":"object","required":["networkId","displayName"],"properties":{"networkId":{"type":"string","description":"CAIP-2 network identifier"},"displayName":{"type":"string","description":"Human-readable network name (e.g. \"Ethereum Mainnet\")"},"explorerUrl":{"type":"string","nullable":true,"description":"Block explorer base URL"},"rpcUrl":{"type":"string","nullable":true,"description":"RPC endpoint URL"},"iconUrl":{"type":"string","nullable":true,"description":"URL of the network icon image"},"nativeCurrencySymbol":{"type":"string","nullable":true,"description":"Native currency ticker (e.g. \"ETH\")"},"nativeCurrencyDecimals":{"type":"integer","nullable":true,"description":"Native currency decimal places"}}}}},"paths":{"/v3/platform/networks":{"get":{"operationId":"listNetworks","summary":"List supported blockchain networks","tags":["Platform"],"description":"List all supported blockchain networks","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["networks"],"properties":{"networks":{"type":"array","items":{"$ref":"#/components/schemas/Network"}}}}}}}}}}}}
```

## List supported tokens

> List all supported tokens with optional filters. No authentication required, but authenticated requests may receive increased rate limits.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Platform","description":"General platform endpoints"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]},{}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"Token":{"type":"object","required":["id","address","networkId","symbol","decimals"],"properties":{"id":{"type":"string","format":"uuid","description":"Token unique identifier"},"address":{"type":"string","description":"Token contract address"},"networkId":{"type":"string","description":"CAIP-2 network identifier"},"symbol":{"type":"string","description":"Token ticker symbol (e.g. \"USDC\", \"WETH\")"},"name":{"type":"string","nullable":true,"description":"Full token name"},"decimals":{"type":"integer","minimum":0,"maximum":255,"description":"Number of decimal places for the token"},"wraps":{"type":"string","nullable":true,"description":"Underlying asset this token represents (e.g. \"USD\" for USDC, \"ETH\" for WETH)"},"iconUrl":{"type":"string","nullable":true,"description":"URL of the token icon image"},"coingeckoId":{"type":"string","nullable":true,"description":"CoinGecko API identifier for price lookups"}}}}},"paths":{"/v3/platform/tokens":{"get":{"operationId":"listTokens","summary":"List supported tokens","tags":["Platform"],"description":"List all supported tokens with optional filters. No authentication required, but authenticated requests may receive increased rate limits.","parameters":[{"schema":{"type":"string"},"in":"query","name":"address","required":false,"description":"Filter by contract address (0x...). Example: 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"},{"schema":{"type":"string"},"in":"query","name":"networkId","required":false,"description":"Filter by CAIP-2 network ID (e.g. eip155:8453)"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["tokens"],"properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/Token"}}}}}}}}}}}}
```

## Get platform statistics

> Get all platform statistics in a single response. No authentication required, but authenticated requests may receive increased rate limits.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Platform","description":"General platform endpoints"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]},{}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}}},"paths":{"/v3/platform/stats":{"get":{"operationId":"getPlatformStats","summary":"Get platform statistics","tags":["Platform"],"description":"Get all platform statistics in a single response. No authentication required, but authenticated requests may receive increased rate limits.","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["totalVolumeUsd","activeLoansUsd","totalInterestPaidUsd","totalBorrowedUsd","borrowCount","repayCount","repayPrincipalCount","repayInterestCount"],"properties":{"totalVolumeUsd":{"type":"string","description":"Total volume in USD (borrows + repayments). Returned as a string to avoid floating-point precision loss."},"activeLoansUsd":{"type":"string","description":"Current outstanding principal in USD. Returned as a string to avoid floating-point precision loss."},"totalInterestPaidUsd":{"type":"string","description":"Total interest paid in USD. Returned as a string to avoid floating-point precision loss."},"totalBorrowedUsd":{"type":"string","description":"Cumulative total borrowed in USD (all time). Returned as a string to avoid floating-point precision loss."},"borrowCount":{"type":"integer","description":"Total number of borrow entries across all organizations."},"repayCount":{"type":"integer","description":"Total number of repay entries across all organizations (principal + interest)."},"repayPrincipalCount":{"type":"integer","description":"Number of principal repay entries across all organizations."},"repayInterestCount":{"type":"integer","description":"Number of interest repay entries across all organizations."}}}}}}}}}}}
```

## Get vault APYs

> Get APY for all lending vaults from sharePrice snapshots. No authentication required, but authenticated requests may receive increased rate limits.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Platform","description":"General platform endpoints"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]},{}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}}},"paths":{"/v3/platform/stats/vault-apys":{"get":{"operationId":"getPlatformVaultApys","summary":"Get vault APYs","tags":["Platform"],"description":"Get APY for all lending vaults from sharePrice snapshots. No authentication required, but authenticated requests may receive increased rate limits.","parameters":[{"schema":{"type":"integer","default":30},"in":"query","name":"period","required":false,"description":"Number of days to look back for APY calculation"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["weightedApyBps","weightedApyPct","totalTvl","periodDays","vaultCount","decimals"],"properties":{"weightedApyBps":{"type":"number","description":"TVL-weighted average APY in basis points"},"weightedApyPct":{"type":"number","description":"TVL-weighted average APY as percentage number (e.g. 8.50 = 8.50%)"},"totalTvl":{"type":"string"},"periodDays":{"type":"number"},"vaultCount":{"type":"number"},"decimals":{"type":"integer","description":"Max decimals used for TVL normalization across vaults"}}}}}}}}}}}
```

## Get platform activity time-series

> Platform-wide borrow/repay totals bucketed by period, with cumulative outstanding. Aggregate-only — no per-borrower data. No authentication required.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Platform","description":"General platform endpoints"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]},{}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}}},"paths":{"/v3/platform/stats/time-series":{"get":{"operationId":"getPlatformTimeSeries","summary":"Get platform activity time-series","tags":["Platform"],"description":"Platform-wide borrow/repay totals bucketed by period, with cumulative outstanding. Aggregate-only — no per-borrower data. No authentication required.","parameters":[{"schema":{"type":"string","maxLength":50},"in":"query","name":"networkId","required":false,"description":"CAIP-2 network filter (e.g. \"eip155:1\")"},{"schema":{"type":"string","format":"date","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"in":"query","name":"startDate","required":false,"description":"Inclusive start date (YYYY-MM-DD)"},{"schema":{"type":"string","format":"date","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"in":"query","name":"endDate","required":false,"description":"Inclusive end date (YYYY-MM-DD)"},{"schema":{"type":"string","enum":["monthly","daily"],"default":"monthly"},"in":"query","name":"granularity","required":false}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["series"],"properties":{"series":{"type":"array","items":{"type":"object","required":["period","borrowUsd","repayPrincipalUsd","repayInterestUsd","netOutstandingUsd","cumulativeVolumeUsd"],"properties":{"period":{"type":"string","description":"'YYYY-MM' (monthly) or 'YYYY-MM-DD' (daily)"},"borrowUsd":{"type":"string","description":"Total borrowed in USD this period."},"repayPrincipalUsd":{"type":"string","description":"Total principal repaid in USD this period."},"repayInterestUsd":{"type":"string","description":"Total interest repaid in USD this period."},"netOutstandingUsd":{"type":"string","description":"Outstanding principal in USD at the end of the period — a point-in-time balance that includes borrowing carried in from before the requested window. Valued at current token prices, not each period's historical price."},"cumulativeVolumeUsd":{"type":"string","description":"Cumulative total volume in USD (borrow + repaid principal + interest) through the end of the period, including volume from before the requested window."}}}}}}}}}}}}}}
```

## Get platform TVL time-series

> Platform-wide TVL bucketed by period, from vault totalAssets() snapshots. Includes disabled vaults. Aggregate-only — no per-borrower data. No authentication required.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Platform","description":"General platform endpoints"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]},{}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}}},"paths":{"/v3/platform/stats/tvl/time-series":{"get":{"operationId":"getPlatformTvlTimeSeries","summary":"Get platform TVL time-series","tags":["Platform"],"description":"Platform-wide TVL bucketed by period, from vault totalAssets() snapshots. Includes disabled vaults. Aggregate-only — no per-borrower data. No authentication required.","parameters":[{"schema":{"type":"string","maxLength":50},"in":"query","name":"networkId","required":false,"description":"CAIP-2 network filter (e.g. \"eip155:1\")"},{"schema":{"type":"string","format":"date","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"in":"query","name":"startDate","required":false,"description":"Inclusive start date (YYYY-MM-DD). Defaults to a safe lookback window."},{"schema":{"type":"string","format":"date","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"in":"query","name":"endDate","required":false,"description":"Inclusive end date (YYYY-MM-DD). Defaults to today (UTC)."},{"schema":{"type":"string","enum":["monthly","daily"],"default":"monthly"},"in":"query","name":"granularity","required":false}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["series"],"properties":{"series":{"type":"array","items":{"type":"object","required":["period","tvl"],"properties":{"period":{"type":"string","description":"'YYYY-MM' (monthly) or 'YYYY-MM-DD' (daily)"},"tvl":{"type":"string","description":"Total value locked in USD at end of period."}}}}}}}}}}}}}}
```

## Get platform weighted-APY time-series

> Platform-wide TVL-weighted APY bucketed by period, from vault sharePrice()/totalAssets() snapshots. Includes disabled vaults. Aggregate-only — no per-borrower data. No authentication required.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Platform","description":"General platform endpoints"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]},{}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}}},"paths":{"/v3/platform/stats/vault-apys/time-series":{"get":{"operationId":"getPlatformVaultApysTimeSeries","summary":"Get platform weighted-APY time-series","tags":["Platform"],"description":"Platform-wide TVL-weighted APY bucketed by period, from vault sharePrice()/totalAssets() snapshots. Includes disabled vaults. Aggregate-only — no per-borrower data. No authentication required.","parameters":[{"schema":{"type":"string","maxLength":50},"in":"query","name":"networkId","required":false,"description":"CAIP-2 network filter (e.g. \"eip155:1\")"},{"schema":{"type":"string","format":"date","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"in":"query","name":"startDate","required":false,"description":"Inclusive start date (YYYY-MM-DD). Defaults to a safe lookback window."},{"schema":{"type":"string","format":"date","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"in":"query","name":"endDate","required":false,"description":"Inclusive end date (YYYY-MM-DD). Defaults to today (UTC)."},{"schema":{"type":"string","enum":["monthly","daily"],"default":"monthly"},"in":"query","name":"granularity","required":false},{"schema":{"type":"integer","default":30,"minimum":1,"maximum":366},"in":"query","name":"period","required":false,"description":"Trailing APY lookback window in days (independent of granularity). Default 30, max 366."}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["series"],"properties":{"series":{"type":"array","items":{"type":"object","required":["period","weightedApyBps","weightedApyPct","totalTvl","decimals","vaultCount"],"properties":{"period":{"type":"string","description":"'YYYY-MM' (monthly) or 'YYYY-MM-DD' (daily)"},"weightedApyBps":{"type":["null","number"],"description":"TVL-weighted APY in basis points; null when no vault has enough history in the bucket."},"weightedApyPct":{"type":["null","number"],"description":"TVL-weighted APY as percentage number (e.g. 8.50 = 8.50%); null mirrors weightedApyBps."},"totalTvl":{"type":"string","description":"Total weight (scaled totalAssets) used for the bucket."},"decimals":{"type":"integer","description":"Max decimals used to normalize the bucket TVL weights."},"vaultCount":{"type":"integer","description":"Vaults that contributed APY + weight to the bucket."}}}}}}}}}}}}}}
```


# Borrowers

Borrower management

## List borrowers

> List enabled borrower organizations. Authentication is optional but affects results.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Borrowers","description":"Borrower management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]},{}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"Organization":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string","format":"uuid","description":"Organization unique identifier"},"name":{"type":"string","maxLength":255,"description":"Organization display name"},"slug":{"type":"string","maxLength":100,"description":"URL-friendly identifier"},"header":{"type":"string","nullable":true,"description":"Short tagline or headline for the organization profile"},"description":{"type":"string","nullable":true,"description":"Brief summary of the organization"},"overview":{"type":"string","nullable":true,"description":"Long-form organization description (may contain Markdown)"},"links":{"type":"array","description":"Organization links and image assets. Labels starting with \"#\" are image assets (e.g. \"#logo\", \"#header\"); all others are external links (e.g. \"Twitter\", \"Website\").","items":{"type":"object","required":["id","label","url"],"properties":{"id":{"type":"string","format":"uuid","description":"Link unique identifier"},"label":{"type":"string","description":"Link type. \"#logo\" and \"#header\" denote image assets; other values (e.g. \"Twitter\", \"Website\") denote external links."},"linkText":{"type":"string","nullable":true,"description":"Display text for external links (e.g. \"@raincards\", \"rain.xyz\")"},"iconUrl":{"type":"string","nullable":true,"description":"Icon image URL for external links"},"url":{"type":"string","description":"Target URL (image URL for asset links, destination URL for external links)"}}}}}},"Pagination":{"type":"object","required":["total","limit","offset"],"properties":{"total":{"type":"integer","description":"Total number of records matching the query"},"limit":{"type":"integer","description":"Maximum number of records returned per page"},"offset":{"type":"integer","description":"Number of records skipped from the start"}}}}},"paths":{"/v3/borrowers":{"get":{"operationId":"listBorrowers","summary":"List borrowers","tags":["Borrowers"],"description":"List enabled borrower organizations. Authentication is optional but affects results.","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"limit","required":false},{"schema":{"type":"integer","minimum":0,"default":0},"in":"query","name":"offset","required":false},{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["v1","v2","v3"]}},"in":"query","name":"protocolVersion","required":false,"description":"Filter by protocol version(s). Comma-separated or repeated (e.g. `?protocolVersion=v1,v2` or `?protocolVersion=v1&protocolVersion=v2`). Omit to return all versions."},{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["organization","stats","apy","status"]}},"in":"query","name":"expand","required":false,"description":"Comma-separated list of fields to expand. Valid values: \"organization\" (includes full organization object with links), \"stats\" (includes borrower statistics), \"apy\" (includes weighted APY and facilities count), \"status\" (includes on-chain cross-default status, one entry per Servicing contract)."}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["borrowers","pagination"],"properties":{"borrowers":{"type":"array","items":{"type":"object","required":["organizationId","name","networkIds"],"properties":{"organizationId":{"type":"string","format":"uuid","description":"Borrower organization ID"},"name":{"type":"string","description":"Organization name"},"networkIds":{"type":"array","items":{"type":"string"},"description":"CAIP-2 network identifiers for blockchain networks this borrower has credit facilities on"},"organization":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Organization"}],"description":"Full organization details with links. Only included when expand includes \"organization\"."},"stats":{"type":"object","nullable":true,"description":"Borrower statistics. Only included when expand includes \"stats\".","required":["totalVolumeUsd","activeLoansUsd","totalInterestPaidUsd","totalBorrowedUsd"],"properties":{"totalVolumeUsd":{"type":"string","description":"Total USD volume (borrows + all repayments)"},"activeLoansUsd":{"type":"string","description":"Current outstanding principal in USD (borrows - principal repayments)"},"totalInterestPaidUsd":{"type":"string","description":"Cumulative interest paid in USD"},"totalBorrowedUsd":{"type":"string","description":"Cumulative amount borrowed in USD (regardless of repayments)"}}},"apy":{"type":"object","nullable":true,"description":"APY and facilities data. Only included when expand includes \"apy\".","required":["facilitiesCount","activeCreditLinesCount"],"properties":{"weightedApyPct":{"type":"number","nullable":true,"description":"Weighted average APY as a percentage (e.g., 8.5 = 8.5%). Null if no credit facility or rates unavailable."},"facilitiesCount":{"type":"number","description":"Number of credit facilities for this borrower."},"activeCreditLinesCount":{"type":"number","description":"Number of open credit lines across all credit facilities for this borrower."}}},"status":{"type":"object","nullable":true,"description":"On-chain cross-default status. Only included when expand includes \"status\". Returns one entry per Servicing contract — each is an independent cross-default group, so they are not merged into a single status.","required":["servicings"],"properties":{"servicings":{"type":"array","items":{"type":"object","required":["address","networkId","closed","isDefaulted","breachLevel","covenants"],"properties":{"address":{"type":"string","description":"Servicing contract address"},"networkId":{"type":"string","nullable":true,"description":"CAIP-2 network identifier (e.g. eip155:8453)"},"closed":{"type":"boolean","nullable":true,"description":"Whether the relationship has been wound down or liquidated. Null when unavailable."},"isDefaulted":{"type":"boolean","nullable":true,"description":"Whether the borrower is in cross-default (applies to every facility under this Servicing). Null when unavailable."},"breachLevel":{"type":"string","nullable":true,"enum":["NONE","CURING","DEFAULTED"],"description":"Worst covenant breach level. CURING is a curable breach within its cure window. Null when it cannot be determined."},"covenants":{"type":"array","items":{"type":"object","required":["address","level"],"properties":{"address":{"type":"string","description":"Covenant contract address"},"level":{"type":"string","nullable":true,"enum":["NONE","CURING","DEFAULTED"],"description":"Breach level for this covenant. Null when its read failed."}}}}}}}}}}}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}}}}}
```

## Get borrower by ID

> Get a single borrower organization by ID. Authentication is optional but required to view private borrowers.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Borrowers","description":"Borrower management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]},{}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"Organization":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string","format":"uuid","description":"Organization unique identifier"},"name":{"type":"string","maxLength":255,"description":"Organization display name"},"slug":{"type":"string","maxLength":100,"description":"URL-friendly identifier"},"header":{"type":"string","nullable":true,"description":"Short tagline or headline for the organization profile"},"description":{"type":"string","nullable":true,"description":"Brief summary of the organization"},"overview":{"type":"string","nullable":true,"description":"Long-form organization description (may contain Markdown)"},"links":{"type":"array","description":"Organization links and image assets. Labels starting with \"#\" are image assets (e.g. \"#logo\", \"#header\"); all others are external links (e.g. \"Twitter\", \"Website\").","items":{"type":"object","required":["id","label","url"],"properties":{"id":{"type":"string","format":"uuid","description":"Link unique identifier"},"label":{"type":"string","description":"Link type. \"#logo\" and \"#header\" denote image assets; other values (e.g. \"Twitter\", \"Website\") denote external links."},"linkText":{"type":"string","nullable":true,"description":"Display text for external links (e.g. \"@raincards\", \"rain.xyz\")"},"iconUrl":{"type":"string","nullable":true,"description":"Icon image URL for external links"},"url":{"type":"string","description":"Target URL (image URL for asset links, destination URL for external links)"}}}}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/borrowers/{id}":{"get":{"operationId":"getBorrower","summary":"Get borrower by ID","tags":["Borrowers"],"description":"Get a single borrower organization by ID. Authentication is optional but required to view private borrowers.","parameters":[{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["organization","stats","apy","status"]}},"in":"query","name":"expand","required":false,"description":"Comma-separated list of fields to expand. Valid values: \"organization\" (includes full organization object with links), \"stats\" (includes borrower statistics), \"apy\" (includes weighted APY and facilities count), \"status\" (includes on-chain cross-default status, one entry per Servicing contract)."},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Borrower organization ID. Example: 550e8400-e29b-41d4-a716-446655440000"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["organizationId","name","networkIds"],"properties":{"organizationId":{"type":"string","format":"uuid","description":"Borrower organization ID"},"name":{"type":"string","description":"Organization name"},"networkIds":{"type":"array","items":{"type":"string"},"description":"CAIP-2 network identifiers for blockchain networks this borrower has credit facilities on"},"organization":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Organization"}],"description":"Full organization details with links. Only included when expand includes \"organization\"."},"stats":{"type":"object","nullable":true,"description":"Borrower statistics. Only included when expand includes \"stats\".","required":["totalVolumeUsd","activeLoansUsd","totalInterestPaidUsd","totalBorrowedUsd"],"properties":{"totalVolumeUsd":{"type":"string","description":"Total USD volume (borrows + all repayments)"},"activeLoansUsd":{"type":"string","description":"Current outstanding principal in USD (borrows - principal repayments)"},"totalInterestPaidUsd":{"type":"string","description":"Cumulative interest paid in USD"},"totalBorrowedUsd":{"type":"string","description":"Cumulative amount borrowed in USD (regardless of repayments)"}}},"apy":{"type":"object","nullable":true,"description":"APY and facilities data. Only included when expand includes \"apy\".","required":["facilitiesCount","activeCreditLinesCount"],"properties":{"weightedApyPct":{"type":"number","nullable":true,"description":"Weighted average APY as a percentage (e.g., 8.5 = 8.5%). Null if no credit facility or rates unavailable."},"facilitiesCount":{"type":"number","description":"Number of credit facilities for this borrower."},"activeCreditLinesCount":{"type":"number","description":"Number of open credit lines across all credit facilities for this borrower."}}},"status":{"type":"object","nullable":true,"description":"On-chain cross-default status. Only included when expand includes \"status\". Returns one entry per Servicing contract — each is an independent cross-default group, so they are not merged into a single status.","required":["servicings"],"properties":{"servicings":{"type":"array","items":{"type":"object","required":["address","networkId","closed","isDefaulted","breachLevel","covenants"],"properties":{"address":{"type":"string","description":"Servicing contract address"},"networkId":{"type":"string","nullable":true,"description":"CAIP-2 network identifier (e.g. eip155:8453)"},"closed":{"type":"boolean","nullable":true,"description":"Whether the relationship has been wound down or liquidated. Null when unavailable."},"isDefaulted":{"type":"boolean","nullable":true,"description":"Whether the borrower is in cross-default (applies to every facility under this Servicing). Null when unavailable."},"breachLevel":{"type":"string","nullable":true,"enum":["NONE","CURING","DEFAULTED"],"description":"Worst covenant breach level. CURING is a curable breach within its cure window. Null when it cannot be determined."},"covenants":{"type":"array","items":{"type":"object","required":["address","level"],"properties":{"address":{"type":"string","description":"Covenant contract address"},"level":{"type":"string","nullable":true,"enum":["NONE","CURING","DEFAULTED"],"description":"Breach level for this covenant. Null when its read failed."}}}}}}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Get borrower activity logs

> Get on-chain activity logs for a borrower. Works for both v2 and v3 borrowers, and contains two kinds of events:\
> \- \*\*Financing events\*\* — borrows/draws, repayments, deposits, withdrawals, fees, and (v3) interest accruals, emitted by the borrower's credit facilities.\
> \- \*\*Status events\*\* (v3 only) — covenant, collateral, and servicing changes.\
> \
> Each item carries a \`source\` (\`facility\`, \`servicing\`, \`covenant\`, or \`collateral\`) indicating which contract emitted it, and \`lineTokenId\` identifying the individual credit line (position) where applicable.\
> \
> Supports three response formats via the \`format\` query parameter:\
> \- \*\*json\*\* (default) — paginated JSON (default limit 20, max 1000).\
> \- \*\*csv\*\* — streamed CSV file download (up to 1 000 000 rows).\
> \- \*\*event-stream\*\* — Server-Sent Events stream (up to 1 000 000 rows). Each log is emitted as a named \`log\` event with JSON data. A final \`done\` event carries \`{"total": N}\`. Connect with \`EventSource\` or \`fetch\`:\
> \
> \`\`\`js\
> const es = new EventSource('/v3/borrowers/{id}/logs?format=event-stream', {\
> &#x20; headers: { 'x-api-key': 'cc\_...' },\
> });\
> es.addEventListener('log', (e) => console.log(JSON.parse(e.data)));\
> es.addEventListener('done', (e) => { console.log('total:', JSON.parse(e.data).total); es.close(); });\
> \`\`\`\
> \
> Event types: AddCredit, RepayPrincipal, RepayInterest, IncreaseCredit, ReservesChanged, Borrow, WithdrawDeposit, WithdrawProfit, PayServicingFee, TransferOriginationFee, Originated, CommitmentDrawn, CommitmentRepaid, CommitmentClaimed, CommitmentAccrued, CommitmentClosed, Refinanced, SurplusClaimed, CloseSurplusRecorded, Closed, CovenantAdded, CovenantRemoved, CovenantEvalFailed, CollateralAdded, CollateralRemoved, AdvanceRateUpdated, CollateralReleased, CollateralReleaseFailed, FacilityAdded, FacilityRemoved, FacilityClosed, FacilityCloseFailed, TrusteeSet, Liquidated, ServicingClosed, BreachDeclared, BreachCured, Checkpointed, Attested, Released, ReleaseFailed, TargetAdded, TargetRemoved, Claimed, OwnerWithdrawn, OperatorUpdated, Operated, TargetReleased, TargetReleaseFailed.

````json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Borrowers","description":"Borrower management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"Pagination":{"type":"object","required":["total","limit","offset"],"properties":{"total":{"type":"integer","description":"Total number of records matching the query"},"limit":{"type":"integer","description":"Maximum number of records returned per page"},"offset":{"type":"integer","description":"Number of records skipped from the start"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/borrowers/{id}/logs":{"get":{"operationId":"getBorrowerLogs","summary":"Get borrower activity logs","tags":["Borrowers"],"description":"Get on-chain activity logs for a borrower. Works for both v2 and v3 borrowers, and contains two kinds of events:\n- **Financing events** — borrows/draws, repayments, deposits, withdrawals, fees, and (v3) interest accruals, emitted by the borrower's credit facilities.\n- **Status events** (v3 only) — covenant, collateral, and servicing changes.\n\nEach item carries a `source` (`facility`, `servicing`, `covenant`, or `collateral`) indicating which contract emitted it, and `lineTokenId` identifying the individual credit line (position) where applicable.\n\nSupports three response formats via the `format` query parameter:\n- **json** (default) — paginated JSON (default limit 20, max 1000).\n- **csv** — streamed CSV file download (up to 1 000 000 rows).\n- **event-stream** — Server-Sent Events stream (up to 1 000 000 rows). Each log is emitted as a named `log` event with JSON data. A final `done` event carries `{\"total\": N}`. Connect with `EventSource` or `fetch`:\n\n```js\nconst es = new EventSource('/v3/borrowers/{id}/logs?format=event-stream', {\n  headers: { 'x-api-key': 'cc_...' },\n});\nes.addEventListener('log', (e) => console.log(JSON.parse(e.data)));\nes.addEventListener('done', (e) => { console.log('total:', JSON.parse(e.data).total); es.close(); });\n```\n\nEvent types: AddCredit, RepayPrincipal, RepayInterest, IncreaseCredit, ReservesChanged, Borrow, WithdrawDeposit, WithdrawProfit, PayServicingFee, TransferOriginationFee, Originated, CommitmentDrawn, CommitmentRepaid, CommitmentClaimed, CommitmentAccrued, CommitmentClosed, Refinanced, SurplusClaimed, CloseSurplusRecorded, Closed, CovenantAdded, CovenantRemoved, CovenantEvalFailed, CollateralAdded, CollateralRemoved, AdvanceRateUpdated, CollateralReleased, CollateralReleaseFailed, FacilityAdded, FacilityRemoved, FacilityClosed, FacilityCloseFailed, TrusteeSet, Liquidated, ServicingClosed, BreachDeclared, BreachCured, Checkpointed, Attested, Released, ReleaseFailed, TargetAdded, TargetRemoved, Claimed, OwnerWithdrawn, OperatorUpdated, Operated, TargetReleased, TargetReleaseFailed.","parameters":[{"schema":{"type":"string","enum":["json","csv","event-stream"],"default":"json"},"in":"query","name":"format","required":false,"description":"Response format. \"json\" returns paginated JSON (default 20, max 1000). \"csv\" returns a streamed CSV file download. \"event-stream\" returns Server-Sent Events with each log as a named \"log\" event and a final \"done\" event. Event types: AddCredit, RepayPrincipal, RepayInterest, IncreaseCredit, ReservesChanged, Borrow, WithdrawDeposit, WithdrawProfit, PayServicingFee, TransferOriginationFee, Originated, CommitmentDrawn, CommitmentRepaid, CommitmentClaimed, CommitmentAccrued, CommitmentClosed, Refinanced, SurplusClaimed, CloseSurplusRecorded, Closed, CovenantAdded, CovenantRemoved, CovenantEvalFailed, CollateralAdded, CollateralRemoved, AdvanceRateUpdated, CollateralReleased, CollateralReleaseFailed, FacilityAdded, FacilityRemoved, FacilityClosed, FacilityCloseFailed, TrusteeSet, Liquidated, ServicingClosed, BreachDeclared, BreachCured, Checkpointed, Attested, Released, ReleaseFailed, TargetAdded, TargetRemoved, Claimed, OwnerWithdrawn, OperatorUpdated, Operated, TargetReleased, TargetReleaseFailed."},{"schema":{"type":"string"},"in":"query","name":"networkId","required":false,"description":"Filter logs by CAIP-2 network identifier. Example: eip155:8453"},{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["v1","v2","v3"]}},"in":"query","name":"protocolVersion","required":false,"description":"Filter by protocol version(s). Comma-separated or repeated (e.g. `?protocolVersion=v1,v2` or `?protocolVersion=v1&protocolVersion=v2`). Omit to return all versions."},{"schema":{"type":"string","format":"date"},"in":"query","name":"startDate","required":false,"description":"Start date (YYYY-MM-DD). Example: 2025-01-15"},{"schema":{"type":"string","format":"date"},"in":"query","name":"endDate","required":false,"description":"End date, inclusive (YYYY-MM-DD). Example: 2025-01-15"},{"schema":{"type":"integer","minimum":1},"in":"query","name":"limit","required":false,"description":"Maximum number of results. For json: default 20, max 1000. For csv/event-stream: default 1000000, max 1000000."},{"schema":{"type":"integer","minimum":0,"default":0},"in":"query","name":"offset","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Borrower organization ID. Example: 550e8400-e29b-41d4-a716-446655440000"}],"responses":{"200":{"description":"Borrower activity logs — financing events from the borrower's credit facilities (v2 and v3), plus v3 covenant/collateral/servicing status events. Response format depends on the `format` query parameter.","content":{"application/json":{"schema":{"type":"object","required":["organizationId","logs","pagination"],"properties":{"organizationId":{"type":"string","format":"uuid","description":"Borrower organization ID"},"logs":{"type":"array","items":{"type":"object","required":["timestamp","eventType","direction","amount","decimals","token","lineTokenId","address","source","protocolVersion","contractAddress","networkId","txHash"],"properties":{"timestamp":{"type":"string","format":"date-time"},"eventType":{"type":"string","description":"Event type. One of: AddCredit, RepayPrincipal, RepayInterest, IncreaseCredit, ReservesChanged, Borrow, WithdrawDeposit, WithdrawProfit, PayServicingFee, TransferOriginationFee, Originated, CommitmentDrawn, CommitmentRepaid, CommitmentClaimed, CommitmentAccrued, CommitmentClosed, Refinanced, SurplusClaimed, CloseSurplusRecorded, Closed, CovenantAdded, CovenantRemoved, CovenantEvalFailed, CollateralAdded, CollateralRemoved, AdvanceRateUpdated, CollateralReleased, CollateralReleaseFailed, FacilityAdded, FacilityRemoved, FacilityClosed, FacilityCloseFailed, TrusteeSet, Liquidated, ServicingClosed, BreachDeclared, BreachCured, Checkpointed, Attested, Released, ReleaseFailed, TargetAdded, TargetRemoved, Claimed, OwnerWithdrawn, OperatorUpdated, Operated, TargetReleased, TargetReleaseFailed"},"direction":{"type":"string","enum":["in","out","none"],"description":"Cash flow direction: in (deposits/repayments), out (borrows/withdrawals/fees), none (not a facility cash flow — e.g. status/lifecycle events, interest accruals, or collateral adapter sweeps/withdrawals; these may still carry a meaningful amount)"},"amount":{"type":"string","description":"Raw on-chain amount (smallest unit integer string)"},"decimals":{"type":"integer","nullable":true,"description":"Token decimals for converting amount to human-readable form"},"token":{"type":"string","nullable":true,"description":"Token contract address"},"lineTokenId":{"type":"string","nullable":true,"description":"Credit line / commitment token ID"},"address":{"type":"string","nullable":true,"description":"The address a status event concerns (e.g. the covenant, collateral, trustee, or counterparty); null when not applicable."},"source":{"type":"string","enum":["facility","servicing","covenant","collateral"],"description":"The kind of contract that emitted the event. `facility` is the lending contract (financing events, for both v2 and v3); `servicing`, `covenant`, and `collateral` are v3 status events. The individual credit line (position) is given by `lineTokenId`."},"protocolVersion":{"type":"string","enum":["v1","v2","v3"],"description":"Protocol generation of the contract that emitted the event."},"contractAddress":{"type":"string"},"networkId":{"type":"string","description":"CAIP-2 network identifier (e.g. eip155:8453)"},"txHash":{"type":"string"}}}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}},"text/csv":{"schema":{"type":"string","description":"CSV file download. Columns: timestamp, eventType, direction, amount, decimals, token, lineTokenId, contractAddress, networkId, txHash, source, address, protocolVersion."}},"text/event-stream":{"schema":{"type":"string","description":"Server-Sent Events stream. Each log is emitted as a named \"log\" event with JSON data. A final \"done\" event carries {\"total\": N}."}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
````

## Get borrower analytics time series

> Get analytics time series for a borrower. Returns daily cashflow, trailing sums, and debt metrics. Auto-detects loan start date from the first borrow event if startDate is not provided.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Borrowers","description":"Borrower management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/borrowers/{id}/analytics":{"get":{"operationId":"getBorrowerAnalytics","summary":"Get borrower analytics time series","tags":["Borrowers"],"description":"Get analytics time series for a borrower. Returns daily cashflow, trailing sums, and debt metrics. Auto-detects loan start date from the first borrow event if startDate is not provided.","parameters":[{"schema":{"type":"string","format":"date"},"in":"query","name":"startDate","required":false,"description":"Start date (YYYY-MM-DD). Defaults to auto-detected loan start."},{"schema":{"type":"string","format":"date"},"in":"query","name":"endDate","required":false,"description":"End date, inclusive (YYYY-MM-DD). Defaults to today."},{"schema":{"type":"string"},"in":"query","name":"trailingDays","required":false,"description":"Comma-separated trailing periods in days (e.g. \"14,30,120\"). Max: 365. Defaults to org config or \"30\"."},{"schema":{"type":"string"},"in":"query","name":"stages","required":false,"description":"Comma-separated INTERNAL (on-chain) stage filter for cashflow (e.g. \"secured,settled\"). Valid values: in_transit, secured, settled. \"external\" is also accepted for backward compatibility but is ignored here — it does not error and does not affect the internal series; external-business cashflow is a separate series (see externalEntryType / cashFlowDailyExternal). Normally you do not need to specify this parameter. Defaults to org config or \"secured\"."},{"schema":{"type":"string","enum":["inflow","net"]},"in":"query","name":"direction","required":false,"description":"Internal (on-chain) cash flow direction. \"inflow\" counts only inflows. \"net\" computes net flow (inflows - outflows). Defaults to org config or \"inflow\"."},{"schema":{"type":"string","enum":["transfer","daily_cashflow"]},"in":"query","name":"externalEntryType","required":false,"description":"Which external-business source to display: \"transfer\" (individual transactions) or \"daily_cashflow\" (daily aggregates). Defaults to whichever source has data."},{"schema":{"type":"string","enum":["inflow","net"]},"in":"query","name":"externalDirection","required":false,"description":"External-business cash flow direction, independent of the internal direction. Defaults to org config or \"inflow\"."},{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["debt"]}},"in":"query","name":"expand","required":false,"description":"Comma-separated list of fields to expand. Valid values: \"debt\" (adds live on-chain debt state)."},{"schema":{"type":"string","enum":["json","csv"],"default":"json"},"in":"query","name":"format","required":false,"description":"Response format. \"json\" (default) or \"csv\" file download."},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Borrower organization ID"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["organizationId","organizationName","config","timeSeries","meta"],"properties":{"organizationId":{"type":"string","format":"uuid"},"organizationName":{"type":"string"},"config":{"type":"object","properties":{"trailingPeriods":{"type":"array","items":{"type":"integer"}},"stages":{"type":"array","items":{"type":"string"},"description":"Internal (on-chain) stages included"},"direction":{"type":"string","enum":["inflow","net"],"description":"Internal direction"},"externalEntryType":{"type":"string","enum":["transfer","daily_cashflow"],"description":"External source displayed (resolved — may have been auto-picked)"},"externalDirection":{"type":"string","enum":["inflow","net"],"description":"External direction"},"loanStartDate":{"type":"string","nullable":true},"loanEndDate":{"type":"string","nullable":true},"loanTermDays":{"type":"integer","nullable":true,"description":"Loan term in days (loanEndDate - loanStartDate), used as trailing period for SRR/WALD"}}},"timeSeries":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","format":"date"},"cashFlowDaily":{"type":"string","description":"Internal (on-chain) daily cashflow for the selected pipeline stages"},"trailingCashFlows":{"type":"object","additionalProperties":{"type":"string"},"description":"Internal trailing cashflow sums keyed by period (e.g. { \"14\": \"423000.00\", \"30\": \"1523450.00\" })"},"cashFlowDailyExternal":{"type":"string","nullable":true,"description":"External-business daily cashflow (money moving outside the on-chain pipeline). Null when the org has no external-business cashflow in range (see meta.hasExternalCashflow)."},"trailingCashFlowsExternal":{"type":"object","additionalProperties":{"type":"string"},"nullable":true,"description":"External-business trailing cashflow sums keyed by period (e.g. { \"14\": \"423000.00\", \"30\": \"1523450.00\" }). Null when the org has no external-business cashflow in range (see meta.hasExternalCashflow)."},"principal":{"type":"string"},"interestPaid":{"type":"string"},"debt":{"type":"string"},"creditLimit":{"type":"string","nullable":true,"description":"Reconstructed credit limit (sum of AddCredit deposits) as of this date"},"loanTerm":{"type":"string","nullable":true,"description":"Deposit-weighted average loan term (days) of credit lines open on this date"},"dscr":{"type":"string","nullable":true,"description":"DSCR: loan-term-windowed cashflow / credit limit"},"srr":{"type":"string","nullable":true,"description":"SRR (Spigot Repayment Rate): 30d trailing cashflow / credit limit"},"wald":{"type":"string","nullable":true,"description":"WALD (Weighted Avg Liquidity Duration): 30 / SRR (days to repay at current 30d rate)"},"collateral":{"type":"string","nullable":true,"description":"Cumulative collateral snapshot (USD) as of this date"}}}},"currentDebt":{"type":"object","nullable":true,"description":"Live on-chain debt state. Only present when expand=debt.","properties":{"principal":{"type":"string"},"accruedInterest":{"type":"string"},"deposit":{"type":"string"},"totalDebt":{"type":"string"},"facilities":{"type":"array","items":{"type":"object","properties":{"address":{"type":"string"},"networkId":{"type":"string"},"principal":{"type":"string"},"deposit":{"type":"string"},"interestAccrued":{"type":"string"}}}}}},"meta":{"type":"object","properties":{"dataRange":{"type":"object","properties":{"from":{"type":"string"},"to":{"type":"string"}}},"entriesCount":{"type":"integer"},"loanStartDetected":{"type":"boolean"},"hasExternalCashflow":{"type":"boolean","description":"Whether the org has any external-business cashflow in range, in either source (drives whether external figures are shown)"},"externalSourcesAvailable":{"type":"array","items":{"type":"string","enum":["transfer","daily_cashflow"]},"description":"Which external sources hold data in range — the meaningful options for the external source selector"},"externalCashflowLabel":{"type":"string","nullable":true,"description":"Optional display label for the external cashflow series (e.g. 'Borrower Reported'). Null when no label has been set."}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```


# Credit Facilities

Credit facility management

## List credit facilities

> List enabled Credit Facilities. Authentication is required. Users see credit facilities for public orgs plus private orgs they have access to.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Credit Facilities","description":"Credit facility management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"CreditFacility":{"type":"object","required":["id","address","networkId","protocolVersion","label","organizationId"],"properties":{"id":{"type":"string","format":"uuid","description":"Credit facility unique identifier"},"address":{"type":"string","description":"SecuredLine contract address"},"networkId":{"type":"string","description":"CAIP-2 network identifier"},"protocolVersion":{"type":"string","nullable":true,"description":"Credit Coop protocol/contract generation (\"v1\", \"v2\", or \"v3\"). Determines which fields apply — several facility and credit-line fields are v3 only. Null when not classified."},"label":{"type":"string","nullable":true,"description":"Display label for the credit facility. Always present; null if not configured."},"organizationId":{"type":"string","format":"uuid","nullable":true,"description":"Borrower organization ID"},"organization":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Organization"}],"description":"Organization details with links. Only included when expand includes \"organization\"."},"relatedAddresses":{"type":"object","nullable":true,"description":"On-chain related addresses. Only included when expand includes \"related-addresses\".","properties":{"spigot":{"type":"string","nullable":true,"description":"v1/v2 only. Spigot contract address. Captures and routes borrower revenue to debt repayment. Null for v3 facilities (no spigot layer)."},"borrower":{"type":"string","nullable":true,"description":"Address authorized to borrow, repay, and close credit lines. Present on all versions."},"admin":{"type":"string","nullable":true,"description":"v1/v2 only. Credit facility administrator address. Null for v3 facilities."},"spigotOperator":{"type":"string","nullable":true,"description":"v1/v2 only. Address authorized to execute revenue claims on the Spigot. Null for v3 facilities."},"escrow":{"type":"string","nullable":true,"description":"v2 only. Escrow contract address. Holds collateral posted by the borrower and enforces the minimum collateral ratio. Null for v1/v3 facilities (v3 collateral lives on the Servicing contract)."},"servicing":{"type":"string","nullable":true,"description":"v3 only. The facility's bound Servicing contract — the per-borrower hub for covenants, collateral, and cross-default. Null for v1/v2 facilities."},"servicingId":{"type":"string","format":"uuid","nullable":true,"description":"v3 only. Resource ID of the bound Servicing (use with GET /v3/servicings/:id). Null when the Servicing address is not registered, or for v1/v2 facilities."},"commitmentToken":{"type":"string","nullable":true,"description":"v3 only. The ERC-721 CommitmentToken singleton — the NFT contract representing every commitment/credit line in the facility (ownerOf(lineTokenId) is the lender). Facility-wide: the same contract for every line. Null for v1/v2 facilities (no commitment-NFT layer)."}}},"fees":{"type":"object","nullable":true,"description":"Fee configuration for the Credit Facility. Only included when expand includes \"fees\".","required":["originationFee","swapFee","servicingFee","drawFee","repayFee"],"properties":{"originationFee":{"type":"string","nullable":true,"description":"Origination fee (basis points). Present on v2 and v3."},"swapFee":{"type":"string","nullable":true,"description":"v2 only. Swap fee (basis points). Null for v3."},"servicingFee":{"type":"string","nullable":true,"description":"v2 only. Servicing fee (basis points). Null for v3."},"drawFee":{"type":"string","nullable":true,"description":"v3 only. Per-draw fee (basis points, FEE_DRAW). Null for v1/v2."},"repayFee":{"type":"string","nullable":true,"description":"v3 only. Per-repay fee (basis points, FEE_REPAY). Null for v1/v2."}}},"counts":{"type":"object","nullable":true,"description":"Active credit lines and open proposals counts. Only included when expand includes \"counts\".","required":["activeCreditLines","openProposals"],"properties":{"activeCreditLines":{"type":"integer","description":"Number of active credit lines"},"openProposals":{"type":"integer","description":"Number of open mutual consent proposals"}}},"status":{"type":"object","nullable":true,"description":"On-chain status for this facility. Only included when expand includes \"status\". An open facility may report LIQUIDATABLE when its borrower is in cross-default; once a facility is closed it reports REPAID and reflects only its own terminal outcome, never absorbing the borrower's wider default state. Borrower-wide default and covenant breach levels are reported per cross-default group on GET /v3/borrowers (expand=status).","required":["code","label","facilityClosed"],"properties":{"code":{"type":"integer","description":"Numeric status code (0: UNINITIALIZED, 1: ACTIVE, 2: LIQUIDATABLE, 3: REPAID, 4: INSOLVENT, 5: ABORTED)"},"label":{"type":"string","enum":["UNINITIALIZED","ACTIVE","LIQUIDATABLE","REPAID","INSOLVENT","ABORTED","UNKNOWN"],"description":"Human-readable status label. UNKNOWN is returned when the on-chain status code is outside the known range (e.g., a new status added by a future contract version)."},"facilityClosed":{"type":"boolean","description":"Whether this specific facility is closed (terminal). Always present whenever status is present (the entire status object is omitted when unavailable). For a closed facility code/label report REPAID; for an open facility they may additionally reflect borrower-wide cross-default (LIQUIDATABLE)."}}},"collateral":{"type":"object","nullable":true,"description":"On-chain collateral state from the Escrow contract. Only included when expand includes \"collateral\". Null when the facility has no escrow, RPC is unavailable, or the facility predates the Escrow architecture.","required":["maxLtvBps","totalOutstandingDebt","collateralValue","ltvBps","targetLtvBps","collateralTokens"],"properties":{"maxLtvBps":{"type":"string","nullable":true,"description":"Maximum loan-to-value ratio allowed for this facility, in basis points (10000 = 100%). Computed server-side as 10000² / minimumCollateralRatio (integer floor). Null when the facility does not enforce a collateral requirement."},"totalOutstandingDebt":{"type":"string","nullable":true,"description":"Total outstanding debt in USD as a formatted decimal string with trailing zeros trimmed (e.g. \"1234.56\"). The debt token's decimals are read from the first active credit position and applied server-side. \"0\" when there are no active positions. Null when the facility does not enforce a collateral requirement."},"collateralValue":{"type":"string","nullable":true,"description":"Collateral value in USD as a formatted decimal string with trailing zeros trimmed (e.g. \"2000\" or \"1999.99\"). Formatted server-side. Null when the facility does not enforce a collateral requirement."},"ltvBps":{"type":"string","nullable":true,"description":"Current loan-to-value ratio in basis points: (totalOutstandingDebt × 10000) / collateralValue, computed server-side from raw on-chain values (decimals normalized before division). \"0\" when there is no outstanding debt. \"999999999\" (sentinel) when debt is positive but on-chain collateral value is 0 — the facility is effectively infinitely undercollateralized. Null when the facility does not enforce a collateral requirement, or when debt decimals could not be resolved."},"targetLtvBps":{"type":"string","nullable":true,"description":"Target LTV in basis points. Defines the minimum collateral value required to back the facility's credit limit (min collateral ≈ creditLimit × 10000 / targetLtvBps). Null when no target is configured for this facility."},"collateralTokens":{"type":"array","description":"Every token ever enabled as collateral on the Escrow, with its current on-chain amount and USD value. May be empty if EnableCollateral events have not been ingested for this Escrow.","items":{"type":"object","required":["address","amount","decimals","usdValue"],"properties":{"address":{"type":"string","description":"Collateral token address (ERC-20)."},"amount":{"type":"string","nullable":true,"description":"Current on-chain collateral amount (raw uint256; divide by `decimals` to get human-readable value). Null if the on-chain `getCollateralData` read failed."},"decimals":{"type":"integer","nullable":true,"description":"Decimals of the collateral token itself (for rendering `amount`). Null if ERC-20 metadata could not be fetched."},"usdValue":{"type":"string","nullable":true,"description":"USD value of the current collateral amount as a human-readable decimal string (e.g. \"1234.56\"), up to 6 decimal places with trailing zeros trimmed. Null if amount, price, or decimals is unavailable."}}}}}},"totals":{"type":"object","nullable":true,"description":"v3 only. Facility-level aggregates for the facility's single asset: native-unit amounts plus `creditLimitUsd` (the total credit limit in USD). Only included when expand includes \"totals\". Null for v1/v2 facilities — their credit lines can use different tokens, so a single-asset total (and one `decimals`) is not meaningful (use the USD totals on GET /v3/credit-facilities/{id}/credit-lines instead). Also null for a v3 facility when the on-chain read is unavailable; use protocolVersion to distinguish the two cases.","required":["totalCommitment","totalDrawn","drawnRate","undrawnRate","token","decimals","creditLimitUsd"],"properties":{"totalCommitment":{"type":"string","nullable":true,"description":"The facility's total committed credit across its active credit lines, raw uint256 — divide by 10^decimals for a human-readable value. Closed lines no longer count toward the commitment."},"creditLimitUsd":{"type":"string","nullable":true,"description":"The facility's total credit limit in USD — totalCommitment priced in `token` at request time, as a human-readable decimal string. Null when totalCommitment is null, decimals is unavailable, or the token is unpriced. (For v1/v2, use creditLimitUsd on GET /v3/credit-facilities/{id}/credit-lines instead.)"},"totalDrawn":{"type":"string","nullable":true,"description":"The facility's total drawn principal across its credit lines, raw uint256 — divide by 10^decimals for a human-readable value."},"drawnRate":{"type":"string","nullable":true,"description":"Facility-default draw rate in basis points (DRAWN_RATE_BPS) — interest on drawn principal. Individual commitments may override this; see each credit line's drawRate for the effective per-line rate. Null if the facility exposes no per-facility rate getter (e.g. TIERED)."},"undrawnRate":{"type":"string","nullable":true,"description":"Facility-default undrawn rate in basis points (UNDRAWN_RATE_BPS) — interest on the undrawn commitment. Individual commitments may override this; see each credit line's facilityRate for the effective per-line rate. Null if the facility exposes no per-facility rate getter (e.g. TIERED)."},"token":{"type":"string","nullable":true,"description":"The single ERC-20 asset every credit line in the facility is denominated in — the unit of totalCommitment and totalDrawn."},"decimals":{"type":"integer","nullable":true,"description":"Decimals of the facility asset (token), for formatting the raw amounts above."}}}}},"Organization":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string","format":"uuid","description":"Organization unique identifier"},"name":{"type":"string","maxLength":255,"description":"Organization display name"},"slug":{"type":"string","maxLength":100,"description":"URL-friendly identifier"},"header":{"type":"string","nullable":true,"description":"Short tagline or headline for the organization profile"},"description":{"type":"string","nullable":true,"description":"Brief summary of the organization"},"overview":{"type":"string","nullable":true,"description":"Long-form organization description (may contain Markdown)"},"links":{"type":"array","description":"Organization links and image assets. Labels starting with \"#\" are image assets (e.g. \"#logo\", \"#header\"); all others are external links (e.g. \"Twitter\", \"Website\").","items":{"type":"object","required":["id","label","url"],"properties":{"id":{"type":"string","format":"uuid","description":"Link unique identifier"},"label":{"type":"string","description":"Link type. \"#logo\" and \"#header\" denote image assets; other values (e.g. \"Twitter\", \"Website\") denote external links."},"linkText":{"type":"string","nullable":true,"description":"Display text for external links (e.g. \"@raincards\", \"rain.xyz\")"},"iconUrl":{"type":"string","nullable":true,"description":"Icon image URL for external links"},"url":{"type":"string","description":"Target URL (image URL for asset links, destination URL for external links)"}}}}}},"Pagination":{"type":"object","required":["total","limit","offset"],"properties":{"total":{"type":"integer","description":"Total number of records matching the query"},"limit":{"type":"integer","description":"Maximum number of records returned per page"},"offset":{"type":"integer","description":"Number of records skipped from the start"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/credit-facilities":{"get":{"operationId":"listCreditFacilities","summary":"List credit facilities","tags":["Credit Facilities"],"description":"List enabled Credit Facilities. Authentication is required. Users see credit facilities for public orgs plus private orgs they have access to.","parameters":[{"schema":{"type":"string","maxLength":36,"format":"uuid"},"in":"query","name":"organizationId","required":false,"description":"Filter by borrower organization ID. Example: 550e8400-e29b-41d4-a716-446655440000"},{"schema":{"type":"string","maxLength":100},"in":"query","name":"address","required":false,"description":"Filter by credit facility address. Case-insensitive when networkId is omitted or is an EVM chain (eip155:*), case-sensitive otherwise."},{"schema":{"type":"string","maxLength":50},"in":"query","name":"networkId","required":false,"description":"Filter by network ID (CAIP-2 blockchain ID), e.g., `eip155:1` (Ethereum), `eip155:137` (Polygon), `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` (Solana)"},{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["v1","v2","v3"]}},"in":"query","name":"protocolVersion","required":false,"description":"Filter by protocol version(s). Comma-separated or repeated (e.g. `?protocolVersion=v1,v2` or `?protocolVersion=v1&protocolVersion=v2`). Omit to return all versions."},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"limit","required":false},{"schema":{"type":"integer","minimum":0,"default":0},"in":"query","name":"offset","required":false},{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["related-addresses","fees","organization","counts","status","collateral"]}},"in":"query","name":"expand","required":false,"description":"Comma-separated list of fields to expand. Valid values: \"related-addresses\" (fetches on-chain addresses: spigot, borrower, admin, spigotOperator, escrow, servicing (v3 only)), \"fees\" (fetches fee configuration: originationFee, swapFee + servicingFee (v2 only), drawFee + repayFee (v3 only)), \"organization\" (includes full organization object with links), \"counts\" (fetches activeCreditLines and openProposals), \"status\" (fetches on-chain contract status), \"collateral\" (fetches on-chain collateral state: maxLtvBps, collateralValue, totalOutstandingDebt, ltvBps, collateralTokens[])."}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["creditFacilities","pagination"],"properties":{"creditFacilities":{"type":"array","items":{"$ref":"#/components/schemas/CreditFacility"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Get credit facility by ID

> Get a single Credit Facility by ID. Authentication is required.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Credit Facilities","description":"Credit facility management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"CreditFacility":{"type":"object","required":["id","address","networkId","protocolVersion","label","organizationId"],"properties":{"id":{"type":"string","format":"uuid","description":"Credit facility unique identifier"},"address":{"type":"string","description":"SecuredLine contract address"},"networkId":{"type":"string","description":"CAIP-2 network identifier"},"protocolVersion":{"type":"string","nullable":true,"description":"Credit Coop protocol/contract generation (\"v1\", \"v2\", or \"v3\"). Determines which fields apply — several facility and credit-line fields are v3 only. Null when not classified."},"label":{"type":"string","nullable":true,"description":"Display label for the credit facility. Always present; null if not configured."},"organizationId":{"type":"string","format":"uuid","nullable":true,"description":"Borrower organization ID"},"organization":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Organization"}],"description":"Organization details with links. Only included when expand includes \"organization\"."},"relatedAddresses":{"type":"object","nullable":true,"description":"On-chain related addresses. Only included when expand includes \"related-addresses\".","properties":{"spigot":{"type":"string","nullable":true,"description":"v1/v2 only. Spigot contract address. Captures and routes borrower revenue to debt repayment. Null for v3 facilities (no spigot layer)."},"borrower":{"type":"string","nullable":true,"description":"Address authorized to borrow, repay, and close credit lines. Present on all versions."},"admin":{"type":"string","nullable":true,"description":"v1/v2 only. Credit facility administrator address. Null for v3 facilities."},"spigotOperator":{"type":"string","nullable":true,"description":"v1/v2 only. Address authorized to execute revenue claims on the Spigot. Null for v3 facilities."},"escrow":{"type":"string","nullable":true,"description":"v2 only. Escrow contract address. Holds collateral posted by the borrower and enforces the minimum collateral ratio. Null for v1/v3 facilities (v3 collateral lives on the Servicing contract)."},"servicing":{"type":"string","nullable":true,"description":"v3 only. The facility's bound Servicing contract — the per-borrower hub for covenants, collateral, and cross-default. Null for v1/v2 facilities."},"servicingId":{"type":"string","format":"uuid","nullable":true,"description":"v3 only. Resource ID of the bound Servicing (use with GET /v3/servicings/:id). Null when the Servicing address is not registered, or for v1/v2 facilities."},"commitmentToken":{"type":"string","nullable":true,"description":"v3 only. The ERC-721 CommitmentToken singleton — the NFT contract representing every commitment/credit line in the facility (ownerOf(lineTokenId) is the lender). Facility-wide: the same contract for every line. Null for v1/v2 facilities (no commitment-NFT layer)."}}},"fees":{"type":"object","nullable":true,"description":"Fee configuration for the Credit Facility. Only included when expand includes \"fees\".","required":["originationFee","swapFee","servicingFee","drawFee","repayFee"],"properties":{"originationFee":{"type":"string","nullable":true,"description":"Origination fee (basis points). Present on v2 and v3."},"swapFee":{"type":"string","nullable":true,"description":"v2 only. Swap fee (basis points). Null for v3."},"servicingFee":{"type":"string","nullable":true,"description":"v2 only. Servicing fee (basis points). Null for v3."},"drawFee":{"type":"string","nullable":true,"description":"v3 only. Per-draw fee (basis points, FEE_DRAW). Null for v1/v2."},"repayFee":{"type":"string","nullable":true,"description":"v3 only. Per-repay fee (basis points, FEE_REPAY). Null for v1/v2."}}},"counts":{"type":"object","nullable":true,"description":"Active credit lines and open proposals counts. Only included when expand includes \"counts\".","required":["activeCreditLines","openProposals"],"properties":{"activeCreditLines":{"type":"integer","description":"Number of active credit lines"},"openProposals":{"type":"integer","description":"Number of open mutual consent proposals"}}},"status":{"type":"object","nullable":true,"description":"On-chain status for this facility. Only included when expand includes \"status\". An open facility may report LIQUIDATABLE when its borrower is in cross-default; once a facility is closed it reports REPAID and reflects only its own terminal outcome, never absorbing the borrower's wider default state. Borrower-wide default and covenant breach levels are reported per cross-default group on GET /v3/borrowers (expand=status).","required":["code","label","facilityClosed"],"properties":{"code":{"type":"integer","description":"Numeric status code (0: UNINITIALIZED, 1: ACTIVE, 2: LIQUIDATABLE, 3: REPAID, 4: INSOLVENT, 5: ABORTED)"},"label":{"type":"string","enum":["UNINITIALIZED","ACTIVE","LIQUIDATABLE","REPAID","INSOLVENT","ABORTED","UNKNOWN"],"description":"Human-readable status label. UNKNOWN is returned when the on-chain status code is outside the known range (e.g., a new status added by a future contract version)."},"facilityClosed":{"type":"boolean","description":"Whether this specific facility is closed (terminal). Always present whenever status is present (the entire status object is omitted when unavailable). For a closed facility code/label report REPAID; for an open facility they may additionally reflect borrower-wide cross-default (LIQUIDATABLE)."}}},"collateral":{"type":"object","nullable":true,"description":"On-chain collateral state from the Escrow contract. Only included when expand includes \"collateral\". Null when the facility has no escrow, RPC is unavailable, or the facility predates the Escrow architecture.","required":["maxLtvBps","totalOutstandingDebt","collateralValue","ltvBps","targetLtvBps","collateralTokens"],"properties":{"maxLtvBps":{"type":"string","nullable":true,"description":"Maximum loan-to-value ratio allowed for this facility, in basis points (10000 = 100%). Computed server-side as 10000² / minimumCollateralRatio (integer floor). Null when the facility does not enforce a collateral requirement."},"totalOutstandingDebt":{"type":"string","nullable":true,"description":"Total outstanding debt in USD as a formatted decimal string with trailing zeros trimmed (e.g. \"1234.56\"). The debt token's decimals are read from the first active credit position and applied server-side. \"0\" when there are no active positions. Null when the facility does not enforce a collateral requirement."},"collateralValue":{"type":"string","nullable":true,"description":"Collateral value in USD as a formatted decimal string with trailing zeros trimmed (e.g. \"2000\" or \"1999.99\"). Formatted server-side. Null when the facility does not enforce a collateral requirement."},"ltvBps":{"type":"string","nullable":true,"description":"Current loan-to-value ratio in basis points: (totalOutstandingDebt × 10000) / collateralValue, computed server-side from raw on-chain values (decimals normalized before division). \"0\" when there is no outstanding debt. \"999999999\" (sentinel) when debt is positive but on-chain collateral value is 0 — the facility is effectively infinitely undercollateralized. Null when the facility does not enforce a collateral requirement, or when debt decimals could not be resolved."},"targetLtvBps":{"type":"string","nullable":true,"description":"Target LTV in basis points. Defines the minimum collateral value required to back the facility's credit limit (min collateral ≈ creditLimit × 10000 / targetLtvBps). Null when no target is configured for this facility."},"collateralTokens":{"type":"array","description":"Every token ever enabled as collateral on the Escrow, with its current on-chain amount and USD value. May be empty if EnableCollateral events have not been ingested for this Escrow.","items":{"type":"object","required":["address","amount","decimals","usdValue"],"properties":{"address":{"type":"string","description":"Collateral token address (ERC-20)."},"amount":{"type":"string","nullable":true,"description":"Current on-chain collateral amount (raw uint256; divide by `decimals` to get human-readable value). Null if the on-chain `getCollateralData` read failed."},"decimals":{"type":"integer","nullable":true,"description":"Decimals of the collateral token itself (for rendering `amount`). Null if ERC-20 metadata could not be fetched."},"usdValue":{"type":"string","nullable":true,"description":"USD value of the current collateral amount as a human-readable decimal string (e.g. \"1234.56\"), up to 6 decimal places with trailing zeros trimmed. Null if amount, price, or decimals is unavailable."}}}}}},"totals":{"type":"object","nullable":true,"description":"v3 only. Facility-level aggregates for the facility's single asset: native-unit amounts plus `creditLimitUsd` (the total credit limit in USD). Only included when expand includes \"totals\". Null for v1/v2 facilities — their credit lines can use different tokens, so a single-asset total (and one `decimals`) is not meaningful (use the USD totals on GET /v3/credit-facilities/{id}/credit-lines instead). Also null for a v3 facility when the on-chain read is unavailable; use protocolVersion to distinguish the two cases.","required":["totalCommitment","totalDrawn","drawnRate","undrawnRate","token","decimals","creditLimitUsd"],"properties":{"totalCommitment":{"type":"string","nullable":true,"description":"The facility's total committed credit across its active credit lines, raw uint256 — divide by 10^decimals for a human-readable value. Closed lines no longer count toward the commitment."},"creditLimitUsd":{"type":"string","nullable":true,"description":"The facility's total credit limit in USD — totalCommitment priced in `token` at request time, as a human-readable decimal string. Null when totalCommitment is null, decimals is unavailable, or the token is unpriced. (For v1/v2, use creditLimitUsd on GET /v3/credit-facilities/{id}/credit-lines instead.)"},"totalDrawn":{"type":"string","nullable":true,"description":"The facility's total drawn principal across its credit lines, raw uint256 — divide by 10^decimals for a human-readable value."},"drawnRate":{"type":"string","nullable":true,"description":"Facility-default draw rate in basis points (DRAWN_RATE_BPS) — interest on drawn principal. Individual commitments may override this; see each credit line's drawRate for the effective per-line rate. Null if the facility exposes no per-facility rate getter (e.g. TIERED)."},"undrawnRate":{"type":"string","nullable":true,"description":"Facility-default undrawn rate in basis points (UNDRAWN_RATE_BPS) — interest on the undrawn commitment. Individual commitments may override this; see each credit line's facilityRate for the effective per-line rate. Null if the facility exposes no per-facility rate getter (e.g. TIERED)."},"token":{"type":"string","nullable":true,"description":"The single ERC-20 asset every credit line in the facility is denominated in — the unit of totalCommitment and totalDrawn."},"decimals":{"type":"integer","nullable":true,"description":"Decimals of the facility asset (token), for formatting the raw amounts above."}}}}},"Organization":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string","format":"uuid","description":"Organization unique identifier"},"name":{"type":"string","maxLength":255,"description":"Organization display name"},"slug":{"type":"string","maxLength":100,"description":"URL-friendly identifier"},"header":{"type":"string","nullable":true,"description":"Short tagline or headline for the organization profile"},"description":{"type":"string","nullable":true,"description":"Brief summary of the organization"},"overview":{"type":"string","nullable":true,"description":"Long-form organization description (may contain Markdown)"},"links":{"type":"array","description":"Organization links and image assets. Labels starting with \"#\" are image assets (e.g. \"#logo\", \"#header\"); all others are external links (e.g. \"Twitter\", \"Website\").","items":{"type":"object","required":["id","label","url"],"properties":{"id":{"type":"string","format":"uuid","description":"Link unique identifier"},"label":{"type":"string","description":"Link type. \"#logo\" and \"#header\" denote image assets; other values (e.g. \"Twitter\", \"Website\") denote external links."},"linkText":{"type":"string","nullable":true,"description":"Display text for external links (e.g. \"@raincards\", \"rain.xyz\")"},"iconUrl":{"type":"string","nullable":true,"description":"Icon image URL for external links"},"url":{"type":"string","description":"Target URL (image URL for asset links, destination URL for external links)"}}}}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/credit-facilities/{id}":{"get":{"operationId":"getCreditFacility","summary":"Get credit facility by ID","tags":["Credit Facilities"],"description":"Get a single Credit Facility by ID. Authentication is required.","parameters":[{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["related-addresses","fees","organization","counts","status","collateral","totals"]}},"in":"query","name":"expand","required":false,"description":"Comma-separated list of fields to expand. Valid values: \"related-addresses\" (fetches on-chain addresses: spigot, borrower, admin, spigotOperator, escrow, servicing + commitmentToken (v3 only)), \"fees\" (fetches fee configuration: originationFee, swapFee + servicingFee (v2 only), drawFee + repayFee (v3 only)), \"organization\" (includes full organization object with links), \"counts\" (fetches activeCreditLines and openProposals), \"status\" (fetches on-chain contract status), \"collateral\" (fetches on-chain collateral state: maxLtvBps, collateralValue, totalOutstandingDebt, ltvBps, collateralTokens[]), \"totals\" (v3 only. fetches facility-level native-unit aggregates: totalCommitment, totalDrawn, drawnRate, undrawnRate, token, decimals. Null for v1/v2 facilities.)."},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Credit Facility ID. Example: 550e8400-e29b-41d4-a716-446655440000"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditFacility"}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Get credit facility credit lines

> Get credit lines for a Credit Facility. Authentication is required.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Credit Facilities","description":"Credit facility management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"CreditLine":{"type":"object","required":["lineTokenId"],"properties":{"lineTokenId":{"type":"string","description":"Credit line token ID"},"deposit":{"type":"string","nullable":true,"description":"Deposit amount (raw uint256 — divide by 10^decimals to get human-readable value)"},"creditLimit":{"type":"string","nullable":true,"description":"Credit limit (raw uint256 — divide by 10^decimals to get human-readable value). For open lines: equals current deposit. For closed lines: deposit from the most recent AddCredit or IncreaseCredit event."},"principal":{"type":"string","nullable":true,"description":"Principal amount borrowed (raw uint256 — divide by 10^decimals to get human-readable value)"},"interestBalance":{"type":"string","nullable":true,"description":"Total interest held by the credit line: the sum of interestAccrued and interestRepaid (raw uint256 — divide by 10^decimals to get human-readable value). v3: equals interestAccrued (repaid proceeds are reported via the claimable field)."},"interestAccrued":{"type":"string","nullable":true,"description":"Interest accrued and owed by the borrower but not yet repaid (raw uint256 — divide by 10^decimals to get human-readable value). v3: equals interestBalance."},"interestRepaid":{"type":"string","nullable":true,"description":"Interest already repaid into the credit line and held for the lender to claim/withdraw (raw uint256 — divide by 10^decimals to get human-readable value). Null for v3 — repaid proceeds are reported in aggregate (principal + interest) via the claimable field."},"token":{"type":"string","nullable":true,"description":"Token address for this credit line"},"decimals":{"type":"integer","nullable":true,"description":"Token decimals"},"isOpen":{"type":"boolean","nullable":true,"description":"Whether the credit line is open"},"isRestricted":{"type":"boolean","nullable":true,"description":"Whether the credit line is restricted. Null for v3 (no equivalent)."},"earlyWithdrawalFee":{"type":"string","nullable":true,"description":"Early withdrawal fee in basis points. Null for v3 (no equivalent)."},"deadline":{"type":"string","format":"date-time","nullable":true,"description":"Credit line deadline"},"drawRate":{"type":"string","nullable":true,"description":"Draw rate in basis points (interest rate on borrowed principal)"},"facilityRate":{"type":"string","nullable":true,"description":"Facility rate in basis points (interest rate on unused deposit)"},"apyPct":{"type":"number","nullable":true,"description":"Computed APY as a percentage (e.g. 5.0 = 5.0%). Weighted average of drawRate on principal and facilityRate on unused deposit."},"createdTxHash":{"type":"string","nullable":true,"description":"Transaction hash of the AddCredit event that created this line"},"createdBlockNumber":{"type":"integer","nullable":true,"description":"Block number when this credit line was created"},"createdAt":{"type":"string","format":"date-time","nullable":true,"description":"Timestamp when this credit line was created. May be null for refinanced commitments."},"commitmentValue":{"type":"string","nullable":true,"description":"v3 only. Canonical par value of the commitment (drawn + interestOwed + claimable + undrawn residual), raw uint256. Null for v2. As of the last on-chain accrual checkpoint."},"claimable":{"type":"string","nullable":true,"description":"v3 only. Repaid/closed proceeds currently claimable by the commitment owner, raw uint256. Null for v2."},"facilityType":{"type":"string","nullable":true,"description":"v3 only. Facility type (\"RCF\" | \"TLA\" | \"DDTL\" | \"TIERED\"). Null for v2."},"isDefaulted":{"type":"boolean","nullable":true,"description":"v3 only. Cross-default (impairment) flag for the position's borrower. Null for v2."},"priority":{"type":"string","nullable":true,"description":"v3 only. Repayment-queue seniority of this commitment (raw uint256; the on-chain terms.priority). Sort by it client-side if you need a strict seniority ordering — the array is not guaranteed to be priority-sorted. Closed lines report `0` (on-chain storage is cleared on close), so drop closed lines before sorting. Null for v1/v2."},"fees":{"type":"object","nullable":true,"description":"Only included when expand=fees is specified. Null if fetching failed.","required":["originationFees"],"properties":{"originationFees":{"type":"string","nullable":true,"description":"Origination fees for this credit line (raw uint256 — divide by 10^decimals to get human-readable value). Null if unavailable."}}},"error":{"type":"string","nullable":true,"description":"Error message if fetching this credit line failed. Other fields will be null."}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/credit-facilities/{id}/credit-lines":{"get":{"operationId":"getCreditFacilityCreditLines","summary":"Get credit facility credit lines","tags":["Credit Facilities"],"description":"Get credit lines for a Credit Facility. Authentication is required.","parameters":[{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["related-addresses","fees"]}},"in":"query","name":"expand","required":false,"description":"Comma-separated list of fields to expand. Valid values: \"related-addresses\" (includes relatedAddresses object with lender, vault, vaultCurator on each credit line), \"fees\" (includes fees object with originationFees on each credit line)."},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Credit Facility ID. Example: 550e8400-e29b-41d4-a716-446655440000"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["facilityId","facilityAddress","networkId","activeCount","totalCount","creditLines","totals"],"properties":{"facilityId":{"type":"string","description":"Credit Facility UUID"},"facilityAddress":{"type":"string","description":"Credit facility contract address"},"networkId":{"type":"string","description":"CAIP-2 network identifier (e.g. eip155:8453)"},"activeCount":{"type":"integer","description":"Number of active credit lines"},"totalCount":{"type":"integer","description":"Total number of credit lines"},"relatedAddresses":{"type":"object","nullable":true,"description":"Facility-level on-chain addresses (distinct from each credit line's own relatedAddresses). Only included when expand includes \"related-addresses\".","required":["commitmentToken"],"properties":{"commitmentToken":{"type":"string","nullable":true,"description":"v3 only. The ERC-721 CommitmentToken singleton — the NFT contract representing every commitment/credit line in the facility (ownerOf(lineTokenId) is the lender). Facility-wide: the same contract for every line. Null for v1/v2 facilities."}}},"fees":{"type":"object","nullable":true,"description":"Fee configuration for the credit facility. Null if fees could not be fetched.","required":["originationFee","swapFee","servicingFee","drawFee","repayFee"],"properties":{"originationFee":{"type":"string","nullable":true,"description":"Origination fee (basis points). Present on v2 and v3."},"swapFee":{"type":"string","nullable":true,"description":"v2 only. Swap fee (basis points). Null for v3."},"servicingFee":{"type":"string","nullable":true,"description":"v2 only. Servicing fee (basis points). Null for v3."},"drawFee":{"type":"string","nullable":true,"description":"v3 only. Per-draw fee (basis points, FEE_DRAW). Null for v1/v2."},"repayFee":{"type":"string","nullable":true,"description":"v3 only. Per-repay fee (basis points, FEE_REPAY). Null for v1/v2."}}},"creditLines":{"type":"array","description":"Credit lines ordered by repayment queue position (first item is repaid first)","items":{"allOf":[{"$ref":"#/components/schemas/CreditLine"},{"type":"object","properties":{"relatedAddresses":{"type":"object","nullable":true,"description":"Related addresses for this credit line. Only included when expand=related-addresses is specified. Contains lender, vault, and vaultCurator addresses. Null if fetching failed.","required":["lender"],"properties":{"lender":{"type":"string","description":"Lender address (owner of the credit line NFT)"},"vault":{"type":"string","nullable":true,"description":"Lending vault address associated with the lender"},"vaultCurator":{"type":"string","nullable":true,"description":"Vault curator address for the lender"}}}}}]}},"totals":{"type":"object","required":["depositUsd","principalUsd","interestAccruedUsd","interestRepaidUsd","interestBalanceUsd","creditLimitUsd"],"description":"Aggregated totals in USD. depositUsd/principalUsd/interestAccruedUsd/interestRepaidUsd/interestBalanceUsd cover all non-errored credit lines (open + closed) — closed lines can still hold non-zero balances on-chain. creditLimitUsd covers OPEN lines only because closed-line creditLimit is the historical authorised credit at close, not an active obligation. apyPct is the USD-deposit-weighted average across open lines. Any USD field is null if a contributing line lacks a USD price.","properties":{"depositUsd":{"type":"string","nullable":true,"description":"Sum across all non-errored lines (open + closed) of deposit converted to USD."},"principalUsd":{"type":"string","nullable":true,"description":"Sum across all non-errored lines (open + closed) of outstanding principal converted to USD."},"interestAccruedUsd":{"type":"string","nullable":true,"description":"Sum across all non-errored lines (open + closed) of accrued interest converted to USD."},"interestRepaidUsd":{"type":"string","nullable":true,"description":"Sum across all non-errored lines (open + closed) of repaid interest converted to USD."},"interestBalanceUsd":{"type":"string","nullable":true,"description":"Sum across all non-errored lines (open + closed) of interest balance converted to USD. Open lines: accrued + repaid. Closed lines: repaid only."},"creditLimitUsd":{"type":"string","nullable":true,"description":"Sum across OPEN credit lines only of creditLimit converted to USD. Closed lines are excluded because their creditLimit is the historical authorised credit at close, not an active obligation."},"apyPct":{"type":"number","nullable":true,"description":"USD-deposit-weighted average APY across open lines (e.g. 5.0 = 5.0%). For multi-token facilities the weighting is in USD so each line contributes proportionally to its USD exposure. Falls back to raw-deposit-weighted APY (with drawRate fallback) when no open line has a priced non-zero deposit. Null if no APY can be derived."}}}}}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Get credit facility proposals

> Get mutual consent proposals for a Credit Facility. Authentication is required.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Credit Facilities","description":"Credit facility management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/credit-facilities/{id}/proposals":{"get":{"operationId":"getCreditFacilityProposals","summary":"Get credit facility proposals","tags":["Credit Facilities"],"description":"Get mutual consent proposals for a Credit Facility. Authentication is required.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Credit Facility ID. Example: 550e8400-e29b-41d4-a716-446655440000"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["facilityId","facilityAddress","networkId","open","closed","revokedAllEvents"],"properties":{"facilityId":{"type":"string","description":"Credit Facility UUID"},"facilityAddress":{"type":"string","description":"Credit facility contract address"},"networkId":{"type":"string","description":"CAIP-2 network identifier (e.g. eip155:8453)"},"open":{"type":"array","description":"Proposals that are still open (pending acceptance)","items":{"type":"object","required":["proposalId","taker","nonce","proposalType","status","registeredAt","registeredTxHash","registeredBlockNumber"],"properties":{"proposalId":{"type":"string","description":"Unique proposal identifier (bytes32)"},"taker":{"type":"string","description":"Address that needs to accept the proposal"},"nonce":{"type":"string","description":"Nonce at time of registration"},"msgData":{"type":"string","nullable":true,"description":"Raw hex-encoded function call data from the proposal"},"proposalType":{"type":"string","enum":["new_credit","refinance","set_fees","unknown"],"description":"Type of proposal: new_credit for new credit lines, refinance for modifications, set_fees for fee changes, unknown if ABI missing or function is not recognized"},"parameters":{"oneOf":[{"title":"CreditProposalParameters","type":"object","description":"Credit proposal parameters (new_credit or refinance)","required":["lender","amount","drawRate","facilityRate","deadline"],"properties":{"lender":{"type":"string","description":"Lender address"},"vaultCurator":{"type":"string","nullable":true,"description":"Vault curator (manager) address for the lender"},"vault":{"type":"string","nullable":true,"description":"Lending vault address for the lender (CreditStrategy)"},"token":{"type":"string","nullable":true,"description":"Token address"},"amount":{"type":"string","description":"Credit amount (raw uint256 — divide by the token's decimals to get human-readable value)"},"drawRate":{"type":"string","description":"Draw rate in basis points"},"facilityRate":{"type":"string","description":"Facility rate in basis points"},"deadline":{"type":"string","format":"date-time","description":"Expiration"},"isRestricted":{"type":"boolean","description":"Whether credit is restricted (new_credit only)"},"earlyWithdrawalFee":{"type":"string","description":"Early withdrawal fee in basis points (new_credit only)"},"lineTokenId":{"type":"string","description":"Existing credit line token ID (refinance only)"},"desiredNonce":{"type":"string","description":"Nonce the proposer required at acceptance, decoded from msgData (new_credit and refinance only)"}}},{"title":"SetFeesProposalParameters","type":"object","description":"Fee change parameters (set_fees)","required":["originationFee","swapFee","servicingFee"],"properties":{"originationFee":{"type":"string","description":"Origination fee in basis points"},"swapFee":{"type":"string","description":"Swap fee in basis points"},"servicingFee":{"type":"string","description":"Servicing fee in basis points"}}},{"type":"null"}],"description":"Decoded proposal terms. Shape depends on proposalType: credit parameters for new_credit/refinance, fee parameters for set_fees, null for unknown."},"status":{"type":"string","enum":["pending"],"description":"Proposal status (always pending for open proposals)"},"registeredAt":{"type":"string","format":"date-time"},"registeredTxHash":{"type":"string"},"registeredBlockNumber":{"type":"integer"}}}},"closed":{"type":"array","description":"Proposals that have been closed (accepted, revoked, or revoked_all)","items":{"type":"object","required":["proposalId","taker","nonce","proposalType","status","registeredAt","registeredTxHash","registeredBlockNumber","closedAt","closedTxHash","closedBlockNumber"],"properties":{"proposalId":{"type":"string","description":"Unique proposal identifier (bytes32)"},"taker":{"type":"string","description":"Address that needed to accept the proposal"},"nonce":{"type":"string","description":"Nonce at time of registration"},"msgData":{"type":"string","nullable":true,"description":"Raw hex-encoded function call data from the proposal"},"proposalType":{"type":"string","enum":["new_credit","refinance","set_fees","unknown"],"description":"Type of proposal: new_credit for new credit lines, refinance for modifications, set_fees for fee changes, unknown if ABI missing or function is not recognized"},"parameters":{"oneOf":[{"title":"CreditProposalParameters","type":"object","description":"Credit proposal parameters (new_credit or refinance)","required":["lender","amount","drawRate","facilityRate","deadline"],"properties":{"lender":{"type":"string","description":"Lender address"},"vaultCurator":{"type":"string","nullable":true,"description":"Vault curator (manager) address for the lender"},"vault":{"type":"string","nullable":true,"description":"Lending vault address for the lender (CreditStrategy)"},"token":{"type":"string","nullable":true,"description":"Token address"},"amount":{"type":"string","description":"Credit amount (raw uint256 — divide by the token's decimals to get human-readable value)"},"drawRate":{"type":"string","description":"Draw rate in basis points"},"facilityRate":{"type":"string","description":"Facility rate in basis points"},"deadline":{"type":"string","format":"date-time","description":"Expiration"},"isRestricted":{"type":"boolean","description":"Whether credit is restricted (new_credit only)"},"earlyWithdrawalFee":{"type":"string","description":"Early withdrawal fee in basis points (new_credit only)"},"lineTokenId":{"type":"string","description":"Existing credit line token ID (refinance only)"},"desiredNonce":{"type":"string","description":"Nonce the proposer required at acceptance, decoded from msgData (new_credit and refinance only)"}}},{"title":"SetFeesProposalParameters","type":"object","description":"Fee change parameters (set_fees)","required":["originationFee","swapFee","servicingFee"],"properties":{"originationFee":{"type":"string","description":"Origination fee in basis points"},"swapFee":{"type":"string","description":"Swap fee in basis points"},"servicingFee":{"type":"string","description":"Servicing fee in basis points"}}},{"type":"null"}],"description":"Decoded proposal terms. Shape depends on proposalType: credit parameters for new_credit/refinance, fee parameters for set_fees, null for unknown."},"status":{"type":"string","enum":["accepted","revoked","revoked_all"],"description":"How the proposal was closed"},"registeredAt":{"type":"string","format":"date-time"},"registeredTxHash":{"type":"string"},"registeredBlockNumber":{"type":"integer"},"closedAt":{"type":"string","format":"date-time"},"closedTxHash":{"type":"string"},"closedBlockNumber":{"type":"integer"}}}},"revokedAllEvents":{"type":"array","description":"All RevokedAll events that cleared proposals","items":{"type":"object","required":["newNonce","timestamp","txHash","blockNumber"],"properties":{"newNonce":{"type":"string","description":"New nonce after revocation"},"timestamp":{"type":"string","format":"date-time"},"txHash":{"type":"string"},"blockNumber":{"type":"integer"}}}}}}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```


# Servicings

Per-borrower servicing relationship hubs. Only applicable to v3 of the protocol — earlier protocol versions do not expose servicings.

## List servicings

> List enabled Servicings (per-borrower relationship hubs). Only applicable to v3 of the protocol. Authentication is required. Users see servicings for borrowers they have access to.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Servicings","description":"Per-borrower servicing relationship hubs. Only applicable to v3 of the protocol — earlier protocol versions do not expose servicings."}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"Servicing":{"type":"object","required":["id","address","networkId","organizationId"],"properties":{"id":{"type":"string","format":"uuid","description":"Servicing unique identifier"},"address":{"type":"string","description":"Servicing contract address"},"networkId":{"type":"string","description":"CAIP-2 network identifier"},"organizationId":{"type":"string","format":"uuid","nullable":true,"description":"Borrower organization ID"},"status":{"type":"object","nullable":true,"description":"On-chain cross-default health of the servicing. Only included when expand includes \"status\".","required":["closed","isDefaulted","breachLevel"],"properties":{"closed":{"type":"boolean","nullable":true,"description":"Whether the servicing has been wound down (terminal). Null when unavailable."},"isDefaulted":{"type":"boolean","nullable":true,"description":"Whether the borrower is in cross-default — one covenant breach gates every facility under this servicing. Null when unavailable."},"breachLevel":{"type":"string","nullable":true,"enum":["NONE","CURING","DEFAULTED"],"description":"Worst covenant breach level across the servicing. Null when it cannot be determined."}}},"asset":{"type":"object","nullable":true,"description":"The accounting unit every raw amount on this servicing (collateral value, capacity) is denominated in. Only included when expand includes \"asset\".","required":["token","decimals"],"properties":{"token":{"type":"string","nullable":true,"description":"Address of the accounting asset. Null when the servicing has no facilities yet or it could not be resolved."},"decimals":{"type":"integer","nullable":true,"description":"Decimals of the accounting asset — divide any raw uint256 amount by 10^decimals to get a human-readable value. Null when unavailable."}}},"organization":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Organization"}],"description":"Organization details with links. Only included when expand includes \"organization\"."},"relatedAddresses":{"type":"object","nullable":true,"description":"Servicer (owner), borrower, and trustee addresses. Only included when expand includes \"related-addresses\".","required":["owner","borrower","trustee"],"properties":{"owner":{"type":"string","nullable":true,"description":"The servicer — the owner of this Servicing hub (gates servicing actions). Distinct from the borrower and trustee."},"borrower":{"type":"string","nullable":true,"description":"The borrower this servicing serves."},"trustee":{"type":"string","nullable":true,"description":"Recipient of seized collateral on liquidation."}}},"collateral":{"type":"array","nullable":true,"description":"The shared collateral pool, one entry per registered collateral. Only included when expand includes \"collateral\".","items":{"type":"object","required":["address","advanceRateBps","value","decimals","valueUsd","level","asset","collateralToken","released","owner"],"properties":{"address":{"type":"string","description":"Collateral contract address."},"advanceRateBps":{"type":"integer","nullable":true,"description":"Share of this collateral's value that counts toward the borrowing base, in basis points (10000 = 100%). Null if unavailable."},"value":{"type":"string","nullable":true,"description":"Raw mark-to-market value (uint256) denominated in `asset` — divide by 10^`decimals` for the human amount. Null if unavailable."},"decimals":{"type":"integer","nullable":true,"description":"Decimals of `asset` — the shared precision of `value` and `valueUsd`. Null when the denomination could not be determined, or when `asset` is known but its on-chain `decimals()` read failed."},"valueUsd":{"type":"string","nullable":true,"description":"USD value as a human-readable decimal string, priced in `asset`. This is the correct number for the LTV sum (the server picks the right per-collateral token). Null when `asset` is unpriced or the denomination could not be determined."},"level":{"type":"string","nullable":true,"enum":["NONE","CURING","DEFAULTED"],"description":"Breach level reported by this collateral. Null if unavailable."},"asset":{"type":"string","nullable":true,"description":"The ERC-20 token that `value` and `valueUsd` are denominated in (so `asset`, `value`, `decimals`, and `valueUsd` are all mutually consistent). For a normal deposited-token collateral this is the same as `collateralToken`. It differs only for a revenue collateral, whose `value` is a fixed appraisal expressed in the facility's accounting unit rather than in the revenue token it collects — there `asset` is that accounting unit. Null when the denomination could not be determined."},"collateralToken":{"type":"string","nullable":true,"description":"The collateral's underlying on-chain token — use this for a \"Token\" column. For a deposited-token collateral it is the escrowed token; for a revenue collateral it is the token the revenue is paid in. Null for a collateral that pledges a contract rather than a token. Usually equals `asset`; it differs only for a revenue collateral (valued in the accounting unit, not the revenue token) — in that case use `valueUsd`/`asset`/`decimals` for the numbers and `collateralToken` only for display."},"released":{"type":"boolean","nullable":true,"description":"Whether this collateral has been released. A released collateral no longer backs the borrowing base, so exclude it when summing `valueUsd` into a collateral-coverage total (its `valueUsd` is still reported). Null if unavailable."},"owner":{"type":"string","nullable":true,"description":"The escrow owner that gates deposit/withdraw actions. Null if unavailable."}}}},"facilities":{"type":"array","nullable":true,"description":"The facilities bound to this servicing. Only included when expand includes \"facilities\".","items":{"type":"object","required":["address","facilityId","organizationId"],"properties":{"address":{"type":"string","description":"Facility contract address."},"facilityId":{"type":"string","format":"uuid","nullable":true,"description":"Resource ID of the facility (use with GET /v3/credit-facilities/:id). Null when the facility address is not registered."},"organizationId":{"type":"string","format":"uuid","nullable":true,"description":"Organization ID of the facility, when registered."}}}},"capacity":{"type":"object","nullable":true,"description":"Shared borrowing-base aggregates across every facility. Only included when expand includes \"capacity\". All amounts are raw uint256 in the accounting unit — divide by 10^decimals.","required":["totalAdvancedValue","totalDrawn","totalCommitted","remainingDrawCapacity","remainingOriginationCapacity"],"properties":{"totalAdvancedValue":{"type":"string","nullable":true,"description":"The shared borrowing base. Null if unavailable."},"totalDrawn":{"type":"string","nullable":true,"description":"Total drawn across all facilities. Null if unavailable."},"totalCommitted":{"type":"string","nullable":true,"description":"Total committed across all facilities. Null if unavailable."},"remainingDrawCapacity":{"type":"string","nullable":true,"description":"Borrowing base remaining for new draws (floored at 0). Null when an input is unavailable."},"remainingOriginationCapacity":{"type":"string","nullable":true,"description":"Borrowing base remaining for new originations (floored at 0). Null when an input is unavailable."}}},"covenants":{"type":"array","nullable":true,"description":"Per-covenant breach levels behind the cross-default status. Only included when expand includes \"covenants\".","items":{"type":"object","required":["address","level","cureWindow"],"properties":{"address":{"type":"string","description":"Covenant contract address."},"level":{"type":"string","nullable":true,"enum":["NONE","CURING","DEFAULTED"],"description":"Breach level for this covenant. Null if unavailable."},"cureWindow":{"type":"string","nullable":true,"description":"Grace period in seconds before a breach escalates from CURING to DEFAULTED. Null if unavailable, or for a collateral entry (collaterals also appear here but expose no cure window)."}}}}}},"Organization":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string","format":"uuid","description":"Organization unique identifier"},"name":{"type":"string","maxLength":255,"description":"Organization display name"},"slug":{"type":"string","maxLength":100,"description":"URL-friendly identifier"},"header":{"type":"string","nullable":true,"description":"Short tagline or headline for the organization profile"},"description":{"type":"string","nullable":true,"description":"Brief summary of the organization"},"overview":{"type":"string","nullable":true,"description":"Long-form organization description (may contain Markdown)"},"links":{"type":"array","description":"Organization links and image assets. Labels starting with \"#\" are image assets (e.g. \"#logo\", \"#header\"); all others are external links (e.g. \"Twitter\", \"Website\").","items":{"type":"object","required":["id","label","url"],"properties":{"id":{"type":"string","format":"uuid","description":"Link unique identifier"},"label":{"type":"string","description":"Link type. \"#logo\" and \"#header\" denote image assets; other values (e.g. \"Twitter\", \"Website\") denote external links."},"linkText":{"type":"string","nullable":true,"description":"Display text for external links (e.g. \"@raincards\", \"rain.xyz\")"},"iconUrl":{"type":"string","nullable":true,"description":"Icon image URL for external links"},"url":{"type":"string","description":"Target URL (image URL for asset links, destination URL for external links)"}}}}}},"Pagination":{"type":"object","required":["total","limit","offset"],"properties":{"total":{"type":"integer","description":"Total number of records matching the query"},"limit":{"type":"integer","description":"Maximum number of records returned per page"},"offset":{"type":"integer","description":"Number of records skipped from the start"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/servicings":{"get":{"operationId":"listServicings","summary":"List servicings","tags":["Servicings"],"description":"List enabled Servicings (per-borrower relationship hubs). Only applicable to v3 of the protocol. Authentication is required. Users see servicings for borrowers they have access to.","parameters":[{"schema":{"type":"string","maxLength":36,"format":"uuid"},"in":"query","name":"organizationId","required":false,"description":"Filter by borrower organization ID. Example: 550e8400-e29b-41d4-a716-446655440000"},{"schema":{"type":"string","maxLength":50},"in":"query","name":"networkId","required":false,"description":"Filter by network ID (CAIP-2 blockchain ID), e.g., `eip155:1` (Ethereum), `eip155:8453` (Base)"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"limit","required":false},{"schema":{"type":"integer","minimum":0,"default":0},"in":"query","name":"offset","required":false},{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["status","asset","organization","related-addresses","collateral","facilities","capacity","covenants"]}},"in":"query","name":"expand","required":false,"description":"Comma-separated list of fields to expand. Valid values: \"status\" (includes the cross-default status (closed, isDefaulted, worst breach level)), \"asset\" (includes the accounting unit (asset token + decimals) every raw amount is denominated in), \"organization\" (includes full organization object with links), \"related-addresses\" (includes the borrower and trustee addresses), \"collateral\" (includes the collateral pool with advance rates, raw value and USD value), \"facilities\" (includes the facilities bound to this servicing), \"capacity\" (includes the shared borrowing-base aggregates (advanced value, drawn, committed, remaining)), \"covenants\" (includes the per-covenant breach levels behind the cross-default status)."}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["servicings","pagination"],"properties":{"servicings":{"type":"array","items":{"$ref":"#/components/schemas/Servicing"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Get servicing by ID

> Get a single Servicing by ID. Only applicable to v3 of the protocol. Authentication is required.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Servicings","description":"Per-borrower servicing relationship hubs. Only applicable to v3 of the protocol — earlier protocol versions do not expose servicings."}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"Servicing":{"type":"object","required":["id","address","networkId","organizationId"],"properties":{"id":{"type":"string","format":"uuid","description":"Servicing unique identifier"},"address":{"type":"string","description":"Servicing contract address"},"networkId":{"type":"string","description":"CAIP-2 network identifier"},"organizationId":{"type":"string","format":"uuid","nullable":true,"description":"Borrower organization ID"},"status":{"type":"object","nullable":true,"description":"On-chain cross-default health of the servicing. Only included when expand includes \"status\".","required":["closed","isDefaulted","breachLevel"],"properties":{"closed":{"type":"boolean","nullable":true,"description":"Whether the servicing has been wound down (terminal). Null when unavailable."},"isDefaulted":{"type":"boolean","nullable":true,"description":"Whether the borrower is in cross-default — one covenant breach gates every facility under this servicing. Null when unavailable."},"breachLevel":{"type":"string","nullable":true,"enum":["NONE","CURING","DEFAULTED"],"description":"Worst covenant breach level across the servicing. Null when it cannot be determined."}}},"asset":{"type":"object","nullable":true,"description":"The accounting unit every raw amount on this servicing (collateral value, capacity) is denominated in. Only included when expand includes \"asset\".","required":["token","decimals"],"properties":{"token":{"type":"string","nullable":true,"description":"Address of the accounting asset. Null when the servicing has no facilities yet or it could not be resolved."},"decimals":{"type":"integer","nullable":true,"description":"Decimals of the accounting asset — divide any raw uint256 amount by 10^decimals to get a human-readable value. Null when unavailable."}}},"organization":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Organization"}],"description":"Organization details with links. Only included when expand includes \"organization\"."},"relatedAddresses":{"type":"object","nullable":true,"description":"Servicer (owner), borrower, and trustee addresses. Only included when expand includes \"related-addresses\".","required":["owner","borrower","trustee"],"properties":{"owner":{"type":"string","nullable":true,"description":"The servicer — the owner of this Servicing hub (gates servicing actions). Distinct from the borrower and trustee."},"borrower":{"type":"string","nullable":true,"description":"The borrower this servicing serves."},"trustee":{"type":"string","nullable":true,"description":"Recipient of seized collateral on liquidation."}}},"collateral":{"type":"array","nullable":true,"description":"The shared collateral pool, one entry per registered collateral. Only included when expand includes \"collateral\".","items":{"type":"object","required":["address","advanceRateBps","value","decimals","valueUsd","level","asset","collateralToken","released","owner"],"properties":{"address":{"type":"string","description":"Collateral contract address."},"advanceRateBps":{"type":"integer","nullable":true,"description":"Share of this collateral's value that counts toward the borrowing base, in basis points (10000 = 100%). Null if unavailable."},"value":{"type":"string","nullable":true,"description":"Raw mark-to-market value (uint256) denominated in `asset` — divide by 10^`decimals` for the human amount. Null if unavailable."},"decimals":{"type":"integer","nullable":true,"description":"Decimals of `asset` — the shared precision of `value` and `valueUsd`. Null when the denomination could not be determined, or when `asset` is known but its on-chain `decimals()` read failed."},"valueUsd":{"type":"string","nullable":true,"description":"USD value as a human-readable decimal string, priced in `asset`. This is the correct number for the LTV sum (the server picks the right per-collateral token). Null when `asset` is unpriced or the denomination could not be determined."},"level":{"type":"string","nullable":true,"enum":["NONE","CURING","DEFAULTED"],"description":"Breach level reported by this collateral. Null if unavailable."},"asset":{"type":"string","nullable":true,"description":"The ERC-20 token that `value` and `valueUsd` are denominated in (so `asset`, `value`, `decimals`, and `valueUsd` are all mutually consistent). For a normal deposited-token collateral this is the same as `collateralToken`. It differs only for a revenue collateral, whose `value` is a fixed appraisal expressed in the facility's accounting unit rather than in the revenue token it collects — there `asset` is that accounting unit. Null when the denomination could not be determined."},"collateralToken":{"type":"string","nullable":true,"description":"The collateral's underlying on-chain token — use this for a \"Token\" column. For a deposited-token collateral it is the escrowed token; for a revenue collateral it is the token the revenue is paid in. Null for a collateral that pledges a contract rather than a token. Usually equals `asset`; it differs only for a revenue collateral (valued in the accounting unit, not the revenue token) — in that case use `valueUsd`/`asset`/`decimals` for the numbers and `collateralToken` only for display."},"released":{"type":"boolean","nullable":true,"description":"Whether this collateral has been released. A released collateral no longer backs the borrowing base, so exclude it when summing `valueUsd` into a collateral-coverage total (its `valueUsd` is still reported). Null if unavailable."},"owner":{"type":"string","nullable":true,"description":"The escrow owner that gates deposit/withdraw actions. Null if unavailable."}}}},"facilities":{"type":"array","nullable":true,"description":"The facilities bound to this servicing. Only included when expand includes \"facilities\".","items":{"type":"object","required":["address","facilityId","organizationId"],"properties":{"address":{"type":"string","description":"Facility contract address."},"facilityId":{"type":"string","format":"uuid","nullable":true,"description":"Resource ID of the facility (use with GET /v3/credit-facilities/:id). Null when the facility address is not registered."},"organizationId":{"type":"string","format":"uuid","nullable":true,"description":"Organization ID of the facility, when registered."}}}},"capacity":{"type":"object","nullable":true,"description":"Shared borrowing-base aggregates across every facility. Only included when expand includes \"capacity\". All amounts are raw uint256 in the accounting unit — divide by 10^decimals.","required":["totalAdvancedValue","totalDrawn","totalCommitted","remainingDrawCapacity","remainingOriginationCapacity"],"properties":{"totalAdvancedValue":{"type":"string","nullable":true,"description":"The shared borrowing base. Null if unavailable."},"totalDrawn":{"type":"string","nullable":true,"description":"Total drawn across all facilities. Null if unavailable."},"totalCommitted":{"type":"string","nullable":true,"description":"Total committed across all facilities. Null if unavailable."},"remainingDrawCapacity":{"type":"string","nullable":true,"description":"Borrowing base remaining for new draws (floored at 0). Null when an input is unavailable."},"remainingOriginationCapacity":{"type":"string","nullable":true,"description":"Borrowing base remaining for new originations (floored at 0). Null when an input is unavailable."}}},"covenants":{"type":"array","nullable":true,"description":"Per-covenant breach levels behind the cross-default status. Only included when expand includes \"covenants\".","items":{"type":"object","required":["address","level","cureWindow"],"properties":{"address":{"type":"string","description":"Covenant contract address."},"level":{"type":"string","nullable":true,"enum":["NONE","CURING","DEFAULTED"],"description":"Breach level for this covenant. Null if unavailable."},"cureWindow":{"type":"string","nullable":true,"description":"Grace period in seconds before a breach escalates from CURING to DEFAULTED. Null if unavailable, or for a collateral entry (collaterals also appear here but expose no cure window)."}}}}}},"Organization":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string","format":"uuid","description":"Organization unique identifier"},"name":{"type":"string","maxLength":255,"description":"Organization display name"},"slug":{"type":"string","maxLength":100,"description":"URL-friendly identifier"},"header":{"type":"string","nullable":true,"description":"Short tagline or headline for the organization profile"},"description":{"type":"string","nullable":true,"description":"Brief summary of the organization"},"overview":{"type":"string","nullable":true,"description":"Long-form organization description (may contain Markdown)"},"links":{"type":"array","description":"Organization links and image assets. Labels starting with \"#\" are image assets (e.g. \"#logo\", \"#header\"); all others are external links (e.g. \"Twitter\", \"Website\").","items":{"type":"object","required":["id","label","url"],"properties":{"id":{"type":"string","format":"uuid","description":"Link unique identifier"},"label":{"type":"string","description":"Link type. \"#logo\" and \"#header\" denote image assets; other values (e.g. \"Twitter\", \"Website\") denote external links."},"linkText":{"type":"string","nullable":true,"description":"Display text for external links (e.g. \"@raincards\", \"rain.xyz\")"},"iconUrl":{"type":"string","nullable":true,"description":"Icon image URL for external links"},"url":{"type":"string","description":"Target URL (image URL for asset links, destination URL for external links)"}}}}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/servicings/{id}":{"get":{"operationId":"getServicing","summary":"Get servicing by ID","tags":["Servicings"],"description":"Get a single Servicing by ID. Only applicable to v3 of the protocol. Authentication is required.","parameters":[{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["status","asset","organization","related-addresses","collateral","facilities","capacity","covenants"]}},"in":"query","name":"expand","required":false,"description":"Comma-separated list of fields to expand. Valid values: \"status\" (includes the cross-default status (closed, isDefaulted, worst breach level)), \"asset\" (includes the accounting unit (asset token + decimals) every raw amount is denominated in), \"organization\" (includes full organization object with links), \"related-addresses\" (includes the borrower and trustee addresses), \"collateral\" (includes the collateral pool with advance rates, raw value and USD value), \"facilities\" (includes the facilities bound to this servicing), \"capacity\" (includes the shared borrowing-base aggregates (advanced value, drawn, committed, remaining)), \"covenants\" (includes the per-covenant breach levels behind the cross-default status)."},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Servicing ID. Example: 550e8400-e29b-41d4-a716-446655440000"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Servicing"}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```


# Vault Curators

Vault curator management

## List vault curators

> List enabled vault curator organizations. Authentication is optional but affects results.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Vault Curators","description":"Vault curator management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]},{}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"Organization":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string","format":"uuid","description":"Organization unique identifier"},"name":{"type":"string","maxLength":255,"description":"Organization display name"},"slug":{"type":"string","maxLength":100,"description":"URL-friendly identifier"},"header":{"type":"string","nullable":true,"description":"Short tagline or headline for the organization profile"},"description":{"type":"string","nullable":true,"description":"Brief summary of the organization"},"overview":{"type":"string","nullable":true,"description":"Long-form organization description (may contain Markdown)"},"links":{"type":"array","description":"Organization links and image assets. Labels starting with \"#\" are image assets (e.g. \"#logo\", \"#header\"); all others are external links (e.g. \"Twitter\", \"Website\").","items":{"type":"object","required":["id","label","url"],"properties":{"id":{"type":"string","format":"uuid","description":"Link unique identifier"},"label":{"type":"string","description":"Link type. \"#logo\" and \"#header\" denote image assets; other values (e.g. \"Twitter\", \"Website\") denote external links."},"linkText":{"type":"string","nullable":true,"description":"Display text for external links (e.g. \"@raincards\", \"rain.xyz\")"},"iconUrl":{"type":"string","nullable":true,"description":"Icon image URL for external links"},"url":{"type":"string","description":"Target URL (image URL for asset links, destination URL for external links)"}}}}}},"Pagination":{"type":"object","required":["total","limit","offset"],"properties":{"total":{"type":"integer","description":"Total number of records matching the query"},"limit":{"type":"integer","description":"Maximum number of records returned per page"},"offset":{"type":"integer","description":"Number of records skipped from the start"}}}}},"paths":{"/v3/vault-curators":{"get":{"operationId":"listVaultCurators","summary":"List vault curators","tags":["Vault Curators"],"description":"List enabled vault curator organizations. Authentication is optional but affects results.","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"limit","required":false},{"schema":{"type":"integer","minimum":0,"default":0},"in":"query","name":"offset","required":false},{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["v1","v2","v3"]}},"in":"query","name":"protocolVersion","required":false,"description":"Filter by protocol version(s). Comma-separated or repeated (e.g. `?protocolVersion=v1,v2` or `?protocolVersion=v1&protocolVersion=v2`). Omit to return all versions."},{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["organization"]}},"in":"query","name":"expand","required":false,"description":"Comma-separated list of fields to expand. Valid values: \"organization\" (includes full organization object with links)."}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["vaultCurators","pagination"],"properties":{"vaultCurators":{"type":"array","items":{"type":"object","required":["organizationId","name","networkIds"],"properties":{"organizationId":{"type":"string","format":"uuid","description":"Vault curator organization ID"},"name":{"type":"string","description":"Organization name"},"networkIds":{"type":"array","items":{"type":"string"},"description":"CAIP-2 network identifiers for blockchain networks this vault curator has vaults on"},"organization":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Organization"}],"description":"Full organization details with links. Only included when expand includes \"organization\"."}}}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}}}}}
```

## Get vault curator by ID

> Get a single vault curator organization by ID. Authentication is optional but required to view private vault curators.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Vault Curators","description":"Vault curator management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]},{}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"Organization":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string","format":"uuid","description":"Organization unique identifier"},"name":{"type":"string","maxLength":255,"description":"Organization display name"},"slug":{"type":"string","maxLength":100,"description":"URL-friendly identifier"},"header":{"type":"string","nullable":true,"description":"Short tagline or headline for the organization profile"},"description":{"type":"string","nullable":true,"description":"Brief summary of the organization"},"overview":{"type":"string","nullable":true,"description":"Long-form organization description (may contain Markdown)"},"links":{"type":"array","description":"Organization links and image assets. Labels starting with \"#\" are image assets (e.g. \"#logo\", \"#header\"); all others are external links (e.g. \"Twitter\", \"Website\").","items":{"type":"object","required":["id","label","url"],"properties":{"id":{"type":"string","format":"uuid","description":"Link unique identifier"},"label":{"type":"string","description":"Link type. \"#logo\" and \"#header\" denote image assets; other values (e.g. \"Twitter\", \"Website\") denote external links."},"linkText":{"type":"string","nullable":true,"description":"Display text for external links (e.g. \"@raincards\", \"rain.xyz\")"},"iconUrl":{"type":"string","nullable":true,"description":"Icon image URL for external links"},"url":{"type":"string","description":"Target URL (image URL for asset links, destination URL for external links)"}}}}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/vault-curators/{id}":{"get":{"operationId":"getVaultCurator","summary":"Get vault curator by ID","tags":["Vault Curators"],"description":"Get a single vault curator organization by ID. Authentication is optional but required to view private vault curators.","parameters":[{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["organization"]}},"in":"query","name":"expand","required":false,"description":"Comma-separated list of fields to expand. Valid values: \"organization\" (includes full organization object with links)."},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Vault curator organization ID. Example: 550e8400-e29b-41d4-a716-446655440000"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["organizationId","name","networkIds"],"properties":{"organizationId":{"type":"string","format":"uuid","description":"Vault curator organization ID"},"name":{"type":"string","description":"Organization name"},"networkIds":{"type":"array","items":{"type":"string"},"description":"CAIP-2 network identifiers for blockchain networks this vault curator has vaults on"},"organization":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Organization"}],"description":"Full organization details with links. Only included when expand includes \"organization\"."}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```


# Vaults

Vault management

## List vaults

> List enabled vaults with organization info. Authentication is optional but affects results: unauthenticated requests only see vaults with public organizations, authenticated users see vaults with public orgs plus private orgs they have access to.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Vaults","description":"Vault management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]},{}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"Vault":{"type":"object","required":["id","address","networkId","protocolVersion","label","organizationId","deployedAt"],"properties":{"id":{"type":"string","format":"uuid","description":"Vault unique identifier"},"address":{"type":"string","description":"Vault contract address"},"networkId":{"type":"string","description":"CAIP-2 network identifier"},"protocolVersion":{"type":"string","nullable":true,"description":"Credit Coop protocol/contract generation (\"v1\", \"v2\", or \"v3\"). Determines which fields apply — several facility and credit-line fields are v3 only. Null when not classified."},"label":{"type":"string","nullable":true,"description":"Display label for the vault. Always present; null if not configured."},"organizationId":{"type":"string","format":"uuid","nullable":true,"description":"Vault curator organization ID"},"deployedAt":{"type":"string","format":"date-time","nullable":true,"description":"Timestamp when the vault contract was deployed"},"organization":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Organization"}],"description":"Organization details with links. Only included when expand includes \"organization\"."},"relatedAddresses":{"type":"object","nullable":true,"description":"On-chain related addresses. Only included when expand includes \"related-addresses\".","properties":{"creditStrategy":{"type":"string","nullable":true,"description":"CreditStrategy contract address. Manages credit allocation from vault funds to credit facilities."},"liquidStrategy":{"type":"string","nullable":true,"description":"LiquidStrategy contract address. Manages liquid asset reserves in the vault."},"vaultCurator":{"type":"string","nullable":true,"description":"Vault curator (manager) address of the CreditStrategy contract. Retrieved by calling manager() on the creditStrategy."},"whitelister":{"type":"string","nullable":true,"description":"Access-control authority that gates the vault deposit whitelist. Set per vault. Null for v2 vaults."}}},"assets":{"type":"object","nullable":true,"description":"Asset information. Only included when expand includes \"assets\".","properties":{"assetToken":{"type":"string","nullable":true,"description":"Asset token address"},"shareToken":{"type":"string","nullable":true,"description":"Share token address"},"decimals":{"type":"integer","nullable":true,"description":"Asset token decimals"},"totalAssets":{"type":"string","nullable":true,"description":"Total assets in the vault (raw uint256 — divide by 10^decimals to get human-readable value)"},"totalLiquidAssets":{"type":"string","nullable":true,"description":"Total liquid assets. Vault's balance - total pending deposits - claimable redeem assets + liquid strategy total assets + uninvested credit strategy assets (raw uint256 — divide by 10^decimals to get human-readable value)"},"totalSupply":{"type":"string","nullable":true,"description":"Total supply of vault shares (raw uint256 — divide by 10^decimals to get human-readable value)"},"sharePrice":{"type":"string","nullable":true,"description":"Share price of the vault (raw uint256 — divide by 10^decimals to get human-readable value)"},"baseUnit":{"type":"string","nullable":true,"description":"Minimum accounting unit used by the CreditStrategy for scaling interest calculations (raw uint256). Equal to 10^decimals."},"totalActiveCredit":{"type":"string","nullable":true,"description":"Total active credit from CreditStrategy. Deposits plus accrued and repaid interest for all credit lines (raw uint256 — divide by 10^decimals to get human-readable value)"},"uninvestedCreditAssets":{"type":"string","nullable":true,"description":"Uninvested credit assets. Asset token balance held by CreditStrategy (raw uint256 — divide by 10^decimals to get human-readable value)"}}},"apy":{"type":"object","nullable":true,"description":"APY data from historical sharePrice snapshots. Only included when expand includes \"apy\".","properties":{"apyPct30D":{"type":"number","nullable":true,"description":"30-day APY in percent (e.g. 5.0 = 5%). Null if insufficient snapshot data."}}},"fees":{"type":"object","nullable":true,"description":"Credit strategy fees in basis points. Only included when expand includes \"fees\".","properties":{"managementFee":{"type":"integer","description":"Management fee in basis points (e.g. 200 = 2%)"},"performanceFee":{"type":"integer","description":"Performance fee in basis points (e.g. 1000 = 10%)"}}}}},"Organization":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string","format":"uuid","description":"Organization unique identifier"},"name":{"type":"string","maxLength":255,"description":"Organization display name"},"slug":{"type":"string","maxLength":100,"description":"URL-friendly identifier"},"header":{"type":"string","nullable":true,"description":"Short tagline or headline for the organization profile"},"description":{"type":"string","nullable":true,"description":"Brief summary of the organization"},"overview":{"type":"string","nullable":true,"description":"Long-form organization description (may contain Markdown)"},"links":{"type":"array","description":"Organization links and image assets. Labels starting with \"#\" are image assets (e.g. \"#logo\", \"#header\"); all others are external links (e.g. \"Twitter\", \"Website\").","items":{"type":"object","required":["id","label","url"],"properties":{"id":{"type":"string","format":"uuid","description":"Link unique identifier"},"label":{"type":"string","description":"Link type. \"#logo\" and \"#header\" denote image assets; other values (e.g. \"Twitter\", \"Website\") denote external links."},"linkText":{"type":"string","nullable":true,"description":"Display text for external links (e.g. \"@raincards\", \"rain.xyz\")"},"iconUrl":{"type":"string","nullable":true,"description":"Icon image URL for external links"},"url":{"type":"string","description":"Target URL (image URL for asset links, destination URL for external links)"}}}}}},"Pagination":{"type":"object","required":["total","limit","offset"],"properties":{"total":{"type":"integer","description":"Total number of records matching the query"},"limit":{"type":"integer","description":"Maximum number of records returned per page"},"offset":{"type":"integer","description":"Number of records skipped from the start"}}}}},"paths":{"/v3/vaults":{"get":{"operationId":"listVaults","summary":"List vaults","tags":["Vaults"],"description":"List enabled vaults with organization info. Authentication is optional but affects results: unauthenticated requests only see vaults with public organizations, authenticated users see vaults with public orgs plus private orgs they have access to.","parameters":[{"schema":{"type":"string","maxLength":36,"format":"uuid"},"in":"query","name":"organizationId","required":false,"description":"Filter by vault curator organization ID. Example: 550e8400-e29b-41d4-a716-446655440000"},{"schema":{"type":"string","maxLength":100},"in":"query","name":"address","required":false,"description":"Filter by vault address. Case-insensitive when networkId is omitted or is an EVM chain (eip155:*), case-sensitive otherwise. Example: 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"},{"schema":{"type":"string","maxLength":50},"in":"query","name":"networkId","required":false,"description":"Filter by network ID (CAIP-2 blockchain ID), e.g., `eip155:1` (Ethereum), `eip155:137` (Polygon), `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` (Solana)"},{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["v1","v2","v3"]}},"in":"query","name":"protocolVersion","required":false,"description":"Filter by protocol version(s). Comma-separated or repeated (e.g. `?protocolVersion=v1,v2` or `?protocolVersion=v1&protocolVersion=v2`). Omit to return all versions."},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"limit","required":false},{"schema":{"type":"integer","minimum":0,"default":0},"in":"query","name":"offset","required":false},{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["related-addresses","assets","organization","apy","fees"]}},"in":"query","name":"expand","required":false,"description":"Comma-separated list of fields to expand. Valid values: \"related-addresses\" (fetches on-chain addresses: creditStrategy, liquidStrategy, vaultCurator. creditStrategy/liquidStrategy are v2-only and null for v3 vaults (which have no strategy layer); vaultCurator is the vault owner.), \"assets\" (fetches asset info: assetToken, shareToken, decimals, totalAssets, totalLiquidAssets, totalSupply, sharePrice, baseUnit, totalActiveCredit, uninvestedCreditAssets), \"organization\" (includes full organization object with links), \"apy\" (fetches 30-day APY from historical sharePrice snapshots), \"fees\" (fetches managementFee and performanceFee from creditStrategy in basis points)."}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["vaults","pagination"],"properties":{"vaults":{"type":"array","items":{"$ref":"#/components/schemas/Vault"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}}}}}
```

## Get vault by ID

> Get a single vault by ID with organization info. Authentication is optional but required to view vaults with private organizations. Vaults with public organizations are visible to everyone.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Vaults","description":"Vault management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]},{}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"Vault":{"type":"object","required":["id","address","networkId","protocolVersion","label","organizationId","deployedAt"],"properties":{"id":{"type":"string","format":"uuid","description":"Vault unique identifier"},"address":{"type":"string","description":"Vault contract address"},"networkId":{"type":"string","description":"CAIP-2 network identifier"},"protocolVersion":{"type":"string","nullable":true,"description":"Credit Coop protocol/contract generation (\"v1\", \"v2\", or \"v3\"). Determines which fields apply — several facility and credit-line fields are v3 only. Null when not classified."},"label":{"type":"string","nullable":true,"description":"Display label for the vault. Always present; null if not configured."},"organizationId":{"type":"string","format":"uuid","nullable":true,"description":"Vault curator organization ID"},"deployedAt":{"type":"string","format":"date-time","nullable":true,"description":"Timestamp when the vault contract was deployed"},"organization":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Organization"}],"description":"Organization details with links. Only included when expand includes \"organization\"."},"relatedAddresses":{"type":"object","nullable":true,"description":"On-chain related addresses. Only included when expand includes \"related-addresses\".","properties":{"creditStrategy":{"type":"string","nullable":true,"description":"CreditStrategy contract address. Manages credit allocation from vault funds to credit facilities."},"liquidStrategy":{"type":"string","nullable":true,"description":"LiquidStrategy contract address. Manages liquid asset reserves in the vault."},"vaultCurator":{"type":"string","nullable":true,"description":"Vault curator (manager) address of the CreditStrategy contract. Retrieved by calling manager() on the creditStrategy."},"whitelister":{"type":"string","nullable":true,"description":"Access-control authority that gates the vault deposit whitelist. Set per vault. Null for v2 vaults."}}},"assets":{"type":"object","nullable":true,"description":"Asset information. Only included when expand includes \"assets\".","properties":{"assetToken":{"type":"string","nullable":true,"description":"Asset token address"},"shareToken":{"type":"string","nullable":true,"description":"Share token address"},"decimals":{"type":"integer","nullable":true,"description":"Asset token decimals"},"totalAssets":{"type":"string","nullable":true,"description":"Total assets in the vault (raw uint256 — divide by 10^decimals to get human-readable value)"},"totalLiquidAssets":{"type":"string","nullable":true,"description":"Total liquid assets. Vault's balance - total pending deposits - claimable redeem assets + liquid strategy total assets + uninvested credit strategy assets (raw uint256 — divide by 10^decimals to get human-readable value)"},"totalSupply":{"type":"string","nullable":true,"description":"Total supply of vault shares (raw uint256 — divide by 10^decimals to get human-readable value)"},"sharePrice":{"type":"string","nullable":true,"description":"Share price of the vault (raw uint256 — divide by 10^decimals to get human-readable value)"},"baseUnit":{"type":"string","nullable":true,"description":"Minimum accounting unit used by the CreditStrategy for scaling interest calculations (raw uint256). Equal to 10^decimals."},"totalActiveCredit":{"type":"string","nullable":true,"description":"Total active credit from CreditStrategy. Deposits plus accrued and repaid interest for all credit lines (raw uint256 — divide by 10^decimals to get human-readable value)"},"uninvestedCreditAssets":{"type":"string","nullable":true,"description":"Uninvested credit assets. Asset token balance held by CreditStrategy (raw uint256 — divide by 10^decimals to get human-readable value)"}}},"apy":{"type":"object","nullable":true,"description":"APY data from historical sharePrice snapshots. Only included when expand includes \"apy\".","properties":{"apyPct30D":{"type":"number","nullable":true,"description":"30-day APY in percent (e.g. 5.0 = 5%). Null if insufficient snapshot data."}}},"fees":{"type":"object","nullable":true,"description":"Credit strategy fees in basis points. Only included when expand includes \"fees\".","properties":{"managementFee":{"type":"integer","description":"Management fee in basis points (e.g. 200 = 2%)"},"performanceFee":{"type":"integer","description":"Performance fee in basis points (e.g. 1000 = 10%)"}}}}},"Organization":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string","format":"uuid","description":"Organization unique identifier"},"name":{"type":"string","maxLength":255,"description":"Organization display name"},"slug":{"type":"string","maxLength":100,"description":"URL-friendly identifier"},"header":{"type":"string","nullable":true,"description":"Short tagline or headline for the organization profile"},"description":{"type":"string","nullable":true,"description":"Brief summary of the organization"},"overview":{"type":"string","nullable":true,"description":"Long-form organization description (may contain Markdown)"},"links":{"type":"array","description":"Organization links and image assets. Labels starting with \"#\" are image assets (e.g. \"#logo\", \"#header\"); all others are external links (e.g. \"Twitter\", \"Website\").","items":{"type":"object","required":["id","label","url"],"properties":{"id":{"type":"string","format":"uuid","description":"Link unique identifier"},"label":{"type":"string","description":"Link type. \"#logo\" and \"#header\" denote image assets; other values (e.g. \"Twitter\", \"Website\") denote external links."},"linkText":{"type":"string","nullable":true,"description":"Display text for external links (e.g. \"@raincards\", \"rain.xyz\")"},"iconUrl":{"type":"string","nullable":true,"description":"Icon image URL for external links"},"url":{"type":"string","description":"Target URL (image URL for asset links, destination URL for external links)"}}}}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/vaults/{id}":{"get":{"operationId":"getVault","summary":"Get vault by ID","tags":["Vaults"],"description":"Get a single vault by ID with organization info. Authentication is optional but required to view vaults with private organizations. Vaults with public organizations are visible to everyone.","parameters":[{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["related-addresses","assets","organization","apy","fees"]}},"in":"query","name":"expand","required":false,"description":"Comma-separated list of fields to expand. Valid values: \"related-addresses\" (fetches on-chain addresses: creditStrategy, liquidStrategy, vaultCurator. creditStrategy/liquidStrategy are v2-only and null for v3 vaults (which have no strategy layer); vaultCurator is the vault owner.), \"assets\" (fetches asset info: assetToken, shareToken, decimals, totalAssets, totalLiquidAssets, totalSupply, sharePrice, baseUnit, totalActiveCredit, uninvestedCreditAssets), \"organization\" (includes full organization object with links), \"apy\" (fetches 30-day APY from historical sharePrice snapshots), \"fees\" (fetches managementFee and performanceFee from creditStrategy in basis points)."},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Vault ID. Example: 550e8400-e29b-41d4-a716-446655440000"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Vault"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Get vault event logs

> Get on-chain event logs for a vault.\
> \
> Supports three response formats via the \`format\` query parameter:\
> \- \*\*json\*\* (default) — paginated JSON (default limit 20, max 1000).\
> \- \*\*csv\*\* — streamed CSV file download (up to 1 000 000 rows).\
> \- \*\*event-stream\*\* — Server-Sent Events stream (up to 1 000 000 rows). Each log is emitted as a named \`log\` event with JSON data. A final \`done\` event carries \`{"total": N}\`. Connect with \`EventSource\` or \`fetch\`:\
> \
> \`\`\`js\
> const es = new EventSource('/v3/vaults/{id}/logs?format=event-stream');\
> es.addEventListener('log', (e) => console.log(JSON.parse(e.data)));\
> es.addEventListener('done', (e) => { console.log('total:', JSON.parse(e.data).total); es.close(); });\
> \`\`\`\
> \
> Authentication is optional but required for vaults with private organizations. Events are ordered by most recent first. For v2 vaults this spans the vault contract, its credit strategy, liquid strategy, and credit facilities; for v3 vaults it currently covers the vault contract's own events (ERC-7540 deposit/redeem activity and PositionAdded/PositionRemoved) — facility-level event coverage is still being added.\
> \
> Event types: AddCredit, CancelDepositRequest, CancelRedeemRequest, CommitmentAccrued, CommitmentClaimed, CommitmentClosed, CommitmentDrawn, CommitmentRepaid, Deposit, DepositRequest, IncreaseCredit, ManagerDeposit, ManagerWithdraw, MintManagementShares, MintPerformanceShares, Originated, PositionAdded, PositionRemoved, ProcessDepositRequest, ProcessRedeemRequest, RedeemRequest, Refinanced, SetFee, SetManager, StrategyDeposit, StrategyWithdraw, SwapCreditPositionForTokens, VaultDeposit, VaultWithdraw, Withdraw, WithdrawDeposit, WithdrawProfit.

````json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Vaults","description":"Vault management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]},{}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/vaults/{id}/logs":{"get":{"operationId":"getVaultLogs","summary":"Get vault event logs","tags":["Vaults"],"description":"Get on-chain event logs for a vault.\n\nSupports three response formats via the `format` query parameter:\n- **json** (default) — paginated JSON (default limit 20, max 1000).\n- **csv** — streamed CSV file download (up to 1 000 000 rows).\n- **event-stream** — Server-Sent Events stream (up to 1 000 000 rows). Each log is emitted as a named `log` event with JSON data. A final `done` event carries `{\"total\": N}`. Connect with `EventSource` or `fetch`:\n\n```js\nconst es = new EventSource('/v3/vaults/{id}/logs?format=event-stream');\nes.addEventListener('log', (e) => console.log(JSON.parse(e.data)));\nes.addEventListener('done', (e) => { console.log('total:', JSON.parse(e.data).total); es.close(); });\n```\n\nAuthentication is optional but required for vaults with private organizations. Events are ordered by most recent first. For v2 vaults this spans the vault contract, its credit strategy, liquid strategy, and credit facilities; for v3 vaults it currently covers the vault contract's own events (ERC-7540 deposit/redeem activity and PositionAdded/PositionRemoved) — facility-level event coverage is still being added.\n\nEvent types: AddCredit, CancelDepositRequest, CancelRedeemRequest, CommitmentAccrued, CommitmentClaimed, CommitmentClosed, CommitmentDrawn, CommitmentRepaid, Deposit, DepositRequest, IncreaseCredit, ManagerDeposit, ManagerWithdraw, MintManagementShares, MintPerformanceShares, Originated, PositionAdded, PositionRemoved, ProcessDepositRequest, ProcessRedeemRequest, RedeemRequest, Refinanced, SetFee, SetManager, StrategyDeposit, StrategyWithdraw, SwapCreditPositionForTokens, VaultDeposit, VaultWithdraw, Withdraw, WithdrawDeposit, WithdrawProfit.","parameters":[{"schema":{"type":"string","enum":["json","csv","event-stream"],"default":"json"},"in":"query","name":"format","required":false,"description":"Response format. \"json\" returns paginated JSON (default 20, max 1000). \"csv\" returns a streamed CSV file download. \"event-stream\" returns Server-Sent Events with each log as a named \"log\" event and a final \"done\" event. Event types: AddCredit, CancelDepositRequest, CancelRedeemRequest, CommitmentAccrued, CommitmentClaimed, CommitmentClosed, CommitmentDrawn, CommitmentRepaid, Deposit, DepositRequest, IncreaseCredit, ManagerDeposit, ManagerWithdraw, MintManagementShares, MintPerformanceShares, Originated, PositionAdded, PositionRemoved, ProcessDepositRequest, ProcessRedeemRequest, RedeemRequest, Refinanced, SetFee, SetManager, StrategyDeposit, StrategyWithdraw, SwapCreditPositionForTokens, VaultDeposit, VaultWithdraw, Withdraw, WithdrawDeposit, WithdrawProfit."},{"schema":{"type":"string","format":"date"},"in":"query","name":"startDate","required":false,"description":"Start date (YYYY-MM-DD). Example: 2025-01-15"},{"schema":{"type":"string","format":"date"},"in":"query","name":"endDate","required":false,"description":"End date, inclusive (YYYY-MM-DD). Example: 2025-01-15"},{"schema":{"type":"integer","minimum":1},"in":"query","name":"limit","required":false,"description":"Maximum number of results. For json: default 20, max 1000. For csv/event-stream: default 1000000, max 1000000."},{"schema":{"type":"integer","minimum":0,"default":0},"in":"query","name":"offset","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Vault ID. Example: 550e8400-e29b-41d4-a716-446655440000"}],"responses":{"200":{"description":"Vault event logs. Response format depends on the `format` query parameter.","content":{"application/json":{"schema":{"type":"object","required":["vaultAddress","networkId","logs","pagination"],"properties":{"vaultAddress":{"type":"string","description":"Vault contract address"},"networkId":{"type":"string","nullable":true,"description":"CAIP-2 network identifier (e.g. eip155:1)"},"logs":{"type":"array","items":{"type":"object","required":["timestamp","eventType","contractAddress","txHash"],"properties":{"timestamp":{"type":"string","format":"date-time","description":"Block timestamp"},"eventType":{"type":"string","description":"Event name"},"address":{"type":"string","nullable":true,"description":"Event-specific principal address. Semantics vary by eventType: ERC-7540 request events (DepositRequest, RedeemRequest, ProcessDepositRequest, ProcessRedeemRequest, CancelDepositRequest, CancelRedeemRequest) → controller; Deposit → owner (ERC-4626 share recipient); Withdraw → receiver (asset recipient); ManagerDeposit, ManagerWithdraw, StrategyDeposit, StrategyWithdraw → sender; MintManagementShares, MintPerformanceShares → manager; VaultDeposit, VaultWithdraw → external vault address; WithdrawDeposit, WithdrawProfit → credit line; SwapCreditPositionForTokens → buyer; SetManager → newManager; CreditLineDeposit → credit facility; SetFee → null. Refer to eventType to interpret."},"amount":{"type":"string","nullable":true,"description":"Raw uint256 asset amount (use decimals field to interpret). Set for asset-denominated events. Null for share-only events (RedeemRequest, CancelRedeemRequest, MintManagementShares, MintPerformanceShares)."},"decimals":{"type":"integer","nullable":true,"description":"Token decimals for the amount field"},"token":{"type":"string","nullable":true,"description":"Asset token address for the amount field (when available)"},"shares":{"type":"string","nullable":true,"description":"Raw uint256 vault share count. Set for: Deposit, Withdraw, ProcessDepositRequest, ProcessRedeemRequest (alongside amount), and RedeemRequest, CancelRedeemRequest, MintManagementShares, MintPerformanceShares (shares only, amount is null)."},"shareToken":{"type":"string","nullable":true,"description":"Vault share token address (the vault contract itself). Set whenever shares is non-null."},"contractAddress":{"type":"string","description":"Contract that emitted the event"},"txHash":{"type":"string","description":"Transaction hash"},"lineTokenId":{"type":"string","nullable":true,"description":"Credit line token ID (for CreditLineDeposit events)"},"feeType":{"type":"string","nullable":true,"description":"Fee type: \"management\" or \"performance\" (for SetFee events)"},"managerShares":{"type":"string","nullable":true,"description":"Manager share amount (raw uint256, for MintManagementShares/MintPerformanceShares events only)"},"protocolShares":{"type":"string","nullable":true,"description":"Protocol share amount (raw uint256, for MintManagementShares/MintPerformanceShares events only)"},"protocolTreasury":{"type":"string","nullable":true,"description":"Protocol treasury address (for MintManagementShares/MintPerformanceShares events only)"}}}},"pagination":{"type":"object","required":["total","limit","offset"],"properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}},"text/csv":{"schema":{"type":"string","description":"CSV file download. Columns: timestamp, eventType, address, amount, decimals, token, shares, shareToken, contractAddress, networkId, txHash, lineTokenId, feeType, managerShares, protocolShares, protocolTreasury."}},"text/event-stream":{"schema":{"type":"string","description":"Server-Sent Events stream. Each log is emitted as a named \"log\" event with JSON data. A final \"done\" event carries {\"total\": N}."}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
````

## Get vault historical asset metrics

> Get a daily timeseries of vault asset metrics derived from on-chain snapshots. Returns totalAssets, totalLiquidAssets, sharePrice, and a 30-day rolling APY for each calendar day in the requested range. Authentication is optional but required for vaults with private organizations and may increase rate limits.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Vaults","description":"Vault management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]},{}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/vaults/{id}/historical/assets":{"get":{"operationId":"getVaultHistoricalAssets","summary":"Get vault historical asset metrics","tags":["Vaults"],"description":"Get a daily timeseries of vault asset metrics derived from on-chain snapshots. Returns totalAssets, totalLiquidAssets, sharePrice, and a 30-day rolling APY for each calendar day in the requested range. Authentication is optional but required for vaults with private organizations and may increase rate limits.","parameters":[{"schema":{"type":"string","format":"date"},"in":"query","name":"startDate","required":false,"description":"Start date (YYYY-MM-DD, UTC). Defaults to the earliest available snapshot date."},{"schema":{"type":"string","format":"date"},"in":"query","name":"endDate","required":false,"description":"End date, inclusive (YYYY-MM-DD, UTC). Defaults to the latest available snapshot date."},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Vault ID. Example: 550e8400-e29b-41d4-a716-446655440000"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["vaultAddress","networkId","assetToken","shareToken","decimals","data"],"properties":{"vaultAddress":{"type":"string","description":"Vault contract address"},"networkId":{"type":"string","nullable":true,"description":"CAIP-2 network identifier"},"assetToken":{"type":"string","nullable":true,"description":"Underlying asset token address (ERC-4626 asset())"},"shareToken":{"type":"string","nullable":true,"description":"Vault share token address (ERC-4626 share())"},"decimals":{"type":"number","nullable":true,"description":"Asset token decimals (shared by asset and share tokens)"},"data":{"type":"array","items":{"type":"object","required":["date","totalAssets","totalLiquidAssets","sharePrice","apyPct30D"],"properties":{"date":{"type":"string","description":"Calendar day (YYYY-MM-DD, UTC)"},"totalAssets":{"type":"string","nullable":true,"description":"Total vault assets (raw uint256 — divide by 10^decimals to get human-readable value)"},"totalLiquidAssets":{"type":"string","nullable":true,"description":"Total liquid assets (raw uint256 — divide by 10^decimals to get human-readable value)"},"sharePrice":{"type":"string","nullable":true,"description":"Share price (raw uint256 — divide by 10^decimals to get human-readable value)"},"apyPct30D":{"type":"number","nullable":true,"description":"30-day rolling APY in percent (e.g. 5.25 = 5.25%). Null when fewer than 30 days of snapshot data exist."}}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Get vault credit lines

> Get credit lines for a vault by querying on-chain data from the creditStrategy contract. Authentication is optional but required to view vaults with private organizations. Vaults with public organizations are visible to everyone.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Vaults","description":"Vault management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]},{}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"CreditLine":{"type":"object","required":["lineTokenId"],"properties":{"lineTokenId":{"type":"string","description":"Credit line token ID"},"deposit":{"type":"string","nullable":true,"description":"Deposit amount (raw uint256 — divide by 10^decimals to get human-readable value)"},"creditLimit":{"type":"string","nullable":true,"description":"Credit limit (raw uint256 — divide by 10^decimals to get human-readable value). For open lines: equals current deposit. For closed lines: deposit from the most recent AddCredit or IncreaseCredit event."},"principal":{"type":"string","nullable":true,"description":"Principal amount borrowed (raw uint256 — divide by 10^decimals to get human-readable value)"},"interestBalance":{"type":"string","nullable":true,"description":"Total interest held by the credit line: the sum of interestAccrued and interestRepaid (raw uint256 — divide by 10^decimals to get human-readable value). v3: equals interestAccrued (repaid proceeds are reported via the claimable field)."},"interestAccrued":{"type":"string","nullable":true,"description":"Interest accrued and owed by the borrower but not yet repaid (raw uint256 — divide by 10^decimals to get human-readable value). v3: equals interestBalance."},"interestRepaid":{"type":"string","nullable":true,"description":"Interest already repaid into the credit line and held for the lender to claim/withdraw (raw uint256 — divide by 10^decimals to get human-readable value). Null for v3 — repaid proceeds are reported in aggregate (principal + interest) via the claimable field."},"token":{"type":"string","nullable":true,"description":"Token address for this credit line"},"decimals":{"type":"integer","nullable":true,"description":"Token decimals"},"isOpen":{"type":"boolean","nullable":true,"description":"Whether the credit line is open"},"isRestricted":{"type":"boolean","nullable":true,"description":"Whether the credit line is restricted. Null for v3 (no equivalent)."},"earlyWithdrawalFee":{"type":"string","nullable":true,"description":"Early withdrawal fee in basis points. Null for v3 (no equivalent)."},"deadline":{"type":"string","format":"date-time","nullable":true,"description":"Credit line deadline"},"drawRate":{"type":"string","nullable":true,"description":"Draw rate in basis points (interest rate on borrowed principal)"},"facilityRate":{"type":"string","nullable":true,"description":"Facility rate in basis points (interest rate on unused deposit)"},"apyPct":{"type":"number","nullable":true,"description":"Computed APY as a percentage (e.g. 5.0 = 5.0%). Weighted average of drawRate on principal and facilityRate on unused deposit."},"createdTxHash":{"type":"string","nullable":true,"description":"Transaction hash of the AddCredit event that created this line"},"createdBlockNumber":{"type":"integer","nullable":true,"description":"Block number when this credit line was created"},"createdAt":{"type":"string","format":"date-time","nullable":true,"description":"Timestamp when this credit line was created. May be null for refinanced commitments."},"commitmentValue":{"type":"string","nullable":true,"description":"v3 only. Canonical par value of the commitment (drawn + interestOwed + claimable + undrawn residual), raw uint256. Null for v2. As of the last on-chain accrual checkpoint."},"claimable":{"type":"string","nullable":true,"description":"v3 only. Repaid/closed proceeds currently claimable by the commitment owner, raw uint256. Null for v2."},"facilityType":{"type":"string","nullable":true,"description":"v3 only. Facility type (\"RCF\" | \"TLA\" | \"DDTL\" | \"TIERED\"). Null for v2."},"isDefaulted":{"type":"boolean","nullable":true,"description":"v3 only. Cross-default (impairment) flag for the position's borrower. Null for v2."},"priority":{"type":"string","nullable":true,"description":"v3 only. Repayment-queue seniority of this commitment (raw uint256; the on-chain terms.priority). Sort by it client-side if you need a strict seniority ordering — the array is not guaranteed to be priority-sorted. Closed lines report `0` (on-chain storage is cleared on close), so drop closed lines before sorting. Null for v1/v2."},"fees":{"type":"object","nullable":true,"description":"Only included when expand=fees is specified. Null if fetching failed.","required":["originationFees"],"properties":{"originationFees":{"type":"string","nullable":true,"description":"Origination fees for this credit line (raw uint256 — divide by 10^decimals to get human-readable value). Null if unavailable."}}},"error":{"type":"string","nullable":true,"description":"Error message if fetching this credit line failed. Other fields will be null."}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/vaults/{id}/credit-lines":{"get":{"operationId":"getVaultCreditLines","summary":"Get vault credit lines","tags":["Vaults"],"description":"Get credit lines for a vault by querying on-chain data from the creditStrategy contract. Authentication is optional but required to view vaults with private organizations. Vaults with public organizations are visible to everyone.","parameters":[{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["related-addresses","fees"]}},"in":"query","name":"expand","required":false,"description":"Comma-separated list of fields to expand. Valid values: \"related-addresses\" (includes relatedAddresses with facility address on each credit line), \"fees\" (includes fees with originationFees on each credit line)."},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Vault ID. Example: 550e8400-e29b-41d4-a716-446655440000"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["vaultId","vaultAddress","networkId","creditLines","totals"],"properties":{"vaultId":{"type":"string","format":"uuid","description":"Vault ID"},"vaultAddress":{"type":"string","description":"Vault contract address"},"networkId":{"type":"string","description":"CAIP-2 network identifier"},"creditLines":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/CreditLine"},{"type":"object","properties":{"relatedAddresses":{"type":"object","nullable":true,"description":"Related addresses for this credit line. Present only when expand=related-addresses.","required":["facility","facilityOrganizationId"],"properties":{"facility":{"type":"string","nullable":true,"description":"Facility contract address for this credit line (v2: SecuredLine; v3: credit facility)"},"facilityOrganizationId":{"type":"string","format":"uuid","nullable":true,"description":"Organization ID of the borrower associated with the facility address. Null if the facility address is not registered."},"borrower":{"type":"string","nullable":true,"description":"v3 only. The facility's on-chain borrower address. Null for v2."},"servicing":{"type":"string","nullable":true,"description":"v3 only. The facility's bound Servicing contract address. Null for v2."},"servicingId":{"type":"string","format":"uuid","nullable":true,"description":"v3 only. Resource ID of the bound Servicing (use with GET /v3/servicings/:id). Null when the Servicing address is not registered, or for v2."}}}}}]}},"totals":{"type":"object","required":["deposit","principal","interestAccrued","interestRepaid","interestBalance","decimals"],"description":"Aggregated totals. Values are normalized to the highest decimals across all credit lines. All monetary fields sum across all non-errored lines (open + closed); closed credit lines on-chain can still hold non-zero values.","properties":{"deposit":{"type":"string","description":"Sum across all non-errored credit lines (open + closed) of deposit, normalized to totals.decimals precision"},"principal":{"type":"string","description":"Sum across all non-errored credit lines (open + closed) of principal, normalized to totals.decimals precision"},"interestAccrued":{"type":"string","description":"Sum across all non-errored credit lines (open + closed) of interest accrued, normalized to totals.decimals precision"},"interestRepaid":{"type":"string","description":"Sum across all non-errored credit lines (open + closed) of interest repaid, normalized to totals.decimals precision"},"interestBalance":{"type":"string","description":"Sum across all non-errored credit lines (open + closed) of interest balance, normalized to totals.decimals precision"},"decimals":{"type":"integer","description":"Decimal precision of the totals values"},"depositUsd":{"type":"string","nullable":true,"description":"Sum across all non-errored credit lines (open + closed) of deposit converted to USD. Null if any contributing line lacks a USD price."},"principalUsd":{"type":"string","nullable":true,"description":"Sum across all non-errored credit lines (open + closed) of outstanding principal converted to USD. Null if any contributing line lacks a USD price."},"interestAccruedUsd":{"type":"string","nullable":true,"description":"Sum across all non-errored credit lines (open + closed) of accrued interest converted to USD. Null if any contributing line lacks a USD price."},"interestRepaidUsd":{"type":"string","nullable":true,"description":"Sum across all non-errored credit lines (open + closed) of repaid interest converted to USD. Null if any contributing line lacks a USD price."},"interestBalanceUsd":{"type":"string","nullable":true,"description":"Sum across all non-errored credit lines (open + closed) of interest balance converted to USD. Null if any contributing line lacks a USD price."},"creditLimitUsd":{"type":"string","nullable":true,"description":"Sum across OPEN credit lines only of creditLimit converted to USD. Closed lines are excluded because their creditLimit is the historical authorised credit at close, not an active obligation."}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Get vault liquid strategy

> Get liquid strategy details for a vault. Authentication is optional but required to view vaults with private organizations. Returns external ERC4626 vault positions with share balances and their underlying asset values. v3 vaults have no liquid strategy (idle capital is held directly), so they return an empty \`vaults\` array with \`liquidStrategyAddress\` set to the zero address and null totals.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Vaults","description":"Vault management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]},{}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/vaults/{id}/liquid-strategy":{"get":{"operationId":"getVaultLiquidStrategy","summary":"Get vault liquid strategy","tags":["Vaults"],"description":"Get liquid strategy details for a vault. Authentication is optional but required to view vaults with private organizations. Returns external ERC4626 vault positions with share balances and their underlying asset values. v3 vaults have no liquid strategy (idle capital is held directly), so they return an empty `vaults` array with `liquidStrategyAddress` set to the zero address and null totals.","parameters":[{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["apy"]}},"in":"query","name":"expand","required":false,"description":"Comma-separated list of fields to expand. Valid values: \"apy\" (fetches 30-day APY for each external vault from historical convertToAssets snapshots, and a weighted-average APY in totals)."},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Vault ID. Example: 550e8400-e29b-41d4-a716-446655440000"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["vaultId","vaultAddress","networkId","liquidStrategyAddress","assetToken","decimals","vaults","totals"],"properties":{"vaultId":{"type":"string","format":"uuid","description":"Vault ID"},"vaultAddress":{"type":"string","description":"Vault contract address"},"networkId":{"type":"string","nullable":true,"description":"CAIP-2 network identifier"},"liquidStrategyAddress":{"type":"string","nullable":true,"description":"Liquid strategy contract address"},"assetToken":{"type":"string","nullable":true,"description":"Underlying asset token address shared by all external vaults"},"decimals":{"type":"integer","nullable":true,"description":"Decimal precision of the underlying asset token. Applies to asset-denominated values: totalAssets, uninvestedAssets, vaultAssets, and assetsValue."},"vaults":{"type":"array","items":{"type":"object","required":["address","shares"],"properties":{"address":{"type":"string","description":"External vault contract address"},"name":{"type":"string","nullable":true,"description":"External vault name"},"symbol":{"type":"string","nullable":true,"description":"External vault token symbol"},"shares":{"type":"string","description":"Share balance held by liquid strategy (raw uint256, use shareDecimals for precision)"},"shareDecimals":{"type":"integer","nullable":true,"description":"Decimal precision of the external vault share token. Applies to shares."},"assetsValue":{"type":"string","nullable":true,"description":"Underlying asset value via previewRedeem (raw uint256, use top-level decimals for precision), null if unavailable"},"apy":{"type":"object","nullable":true,"description":"APY data (only present when expand=apy)","properties":{"apyPct30D":{"type":"number","nullable":true,"description":"30-day annualized APY in percent (e.g. 5.25 = 5.25%)"}}}}}},"totals":{"type":"object","properties":{"totalAssets":{"type":"string","nullable":true,"description":"Total assets managed by liquid strategy (raw uint256, use top-level decimals for precision)"},"uninvestedAssets":{"type":"string","nullable":true,"description":"Uninvested asset tokens held by liquid strategy (raw uint256, use top-level decimals for precision)"},"vaultAssets":{"type":"string","nullable":true,"description":"Sum of assets deployed in external vaults (raw uint256, use top-level decimals for precision)"},"apy":{"type":"object","nullable":true,"description":"Weighted average APY across the entire liquid strategy (only present when expand=apy). The denominator is totalAssets (which includes uninvestedAssets at 0% APY), so the figure reflects the strategy's blended return, not just the invested portion.","properties":{"apyPct30D":{"type":"number","nullable":true,"description":"30-day weighted average annualized APY in percent"}}}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Check vault whitelist status

> Check if an address is whitelisted on the vault's credit strategy contract (requires authentication)

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Vaults","description":"Vault management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/vaults/{id}/whitelist-check":{"get":{"operationId":"checkVaultWhitelist","summary":"Check vault whitelist status","tags":["Vaults"],"description":"Check if an address is whitelisted on the vault's credit strategy contract (requires authentication)","parameters":[{"schema":{"type":"string","maxLength":255},"in":"query","name":"address","required":true,"description":"The address to check for whitelisting. Example: 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Vault ID. Example: 550e8400-e29b-41d4-a716-446655440000"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["vaultId","vaultAddress","networkId","address","isWhitelisted"],"properties":{"vaultId":{"type":"string","format":"uuid","description":"Vault ID"},"vaultAddress":{"type":"string","description":"Vault contract address"},"networkId":{"type":"string","description":"CAIP-2 network identifier"},"address":{"type":"string"},"isWhitelisted":{"type":"boolean"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Get vault pending deposits

> Get pending deposit requests for a vault. Requires a role for the vault's organization.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Vaults","description":"Vault management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/vaults/{id}/pending-deposits":{"get":{"operationId":"getVaultPendingDeposits","summary":"Get vault pending deposits","tags":["Vaults"],"description":"Get pending deposit requests for a vault. Requires a role for the vault's organization.","parameters":[{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["requests"]}},"in":"query","name":"expand","required":false,"description":"Comma-separated list of fields to expand. Valid values: \"requests\" (include a global, oldest-first breakdown of the individual deposit requests behind each consolidated pending amount (date + amounts, FIFO))."},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Vault ID. Example: 550e8400-e29b-41d4-a716-446655440000"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["vaultId","vaultAddress","networkId","pendingDeposits","decimals"],"properties":{"vaultId":{"type":"string","format":"uuid","description":"Vault ID"},"vaultAddress":{"type":"string","description":"Vault contract address"},"networkId":{"type":"string","description":"CAIP-2 network identifier"},"pendingDeposits":{"type":"array","items":{"type":"object","required":["controller","pendingAssets"],"properties":{"controller":{"type":"string","description":"ERC-7540 controller address — the account that initiated the async deposit/redeem request. May differ from the eventual share owner."},"pendingAssets":{"type":"string"}}}},"pendingRequests":{"type":"array","description":"Individual deposit requests reconstructed (FIFO) from the consolidated pending amounts, oldest first. Only present when expand includes 'requests'.","items":{"type":"object","required":["controller","requestedAt","amountRequested","amountRemaining","txHash"],"properties":{"controller":{"type":"string","description":"ERC-7540 controller address that initiated the deposit request."},"requestedAt":{"type":"string","format":"date-time","description":"Block timestamp of the deposit request."},"amountRequested":{"type":"string","description":"Original assets requested by this deposit request."},"amountRemaining":{"type":"string","description":"Assets of this request still outstanding under FIFO fulfillment."},"txHash":{"type":"string","description":"Transaction hash of the deposit request."}}}},"decimals":{"type":"integer","nullable":true}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Get vault pending redemptions

> Get pending redemption requests for a vault. Requires a role for the vault's organization.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Vaults","description":"Vault management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/vaults/{id}/pending-redemptions":{"get":{"operationId":"getVaultPendingRedemptions","summary":"Get vault pending redemptions","tags":["Vaults"],"description":"Get pending redemption requests for a vault. Requires a role for the vault's organization.","parameters":[{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["requests"]}},"in":"query","name":"expand","required":false,"description":"Comma-separated list of fields to expand. Valid values: \"requests\" (include a global, oldest-first breakdown of the individual redeem requests behind each consolidated pending amount (date + amounts, FIFO))."},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Vault ID. Example: 550e8400-e29b-41d4-a716-446655440000"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["vaultId","vaultAddress","networkId","pendingRedemptions","decimals"],"properties":{"vaultId":{"type":"string","format":"uuid","description":"Vault ID"},"vaultAddress":{"type":"string","description":"Vault contract address"},"networkId":{"type":"string","description":"CAIP-2 network identifier"},"pendingRedemptions":{"type":"array","items":{"type":"object","required":["controller","pendingShares"],"properties":{"controller":{"type":"string","description":"ERC-7540 controller address — the account that initiated the async deposit/redeem request. May differ from the eventual share owner."},"pendingShares":{"type":"string"}}}},"pendingRequests":{"type":"array","description":"Individual redeem requests reconstructed (FIFO) from the consolidated pending amounts, oldest first. Only present when expand includes 'requests'.","items":{"type":"object","required":["controller","requestedAt","amountRequested","amountRemaining","txHash"],"properties":{"controller":{"type":"string","description":"ERC-7540 controller address that initiated the redeem request."},"requestedAt":{"type":"string","format":"date-time","description":"Block timestamp of the redeem request."},"amountRequested":{"type":"string","description":"Original shares requested by this redeem request."},"amountRemaining":{"type":"string","description":"Shares of this request still outstanding under FIFO fulfillment."},"txHash":{"type":"string","description":"Transaction hash of the redeem request."}}}},"decimals":{"type":"integer","nullable":true}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```


# Depositors

Depositor portfolio and performance metrics

## Get depositor pending deposits

> Get pending deposit requests across all vaults for a given depositor controller address. If networkId is omitted, results span all chains. Requires authentication.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Depositors","description":"Depositor portfolio and performance metrics"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/depositors/pending-deposits":{"get":{"operationId":"getDepositorPendingDeposits","summary":"Get depositor pending deposits","tags":["Depositors"],"description":"Get pending deposit requests across all vaults for a given depositor controller address. If networkId is omitted, results span all chains. Requires authentication.","parameters":[{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["v1","v2","v3"]}},"in":"query","name":"protocolVersion","required":false,"description":"Filter by protocol version(s). Comma-separated or repeated (e.g. `?protocolVersion=v1,v2` or `?protocolVersion=v1&protocolVersion=v2`). Omit to return all versions."},{"schema":{"type":"string","maxLength":200},"in":"query","name":"address","required":true,"description":"Depositor controller address to look up pending deposits for. The controller is the address that initiated the ERC-7540 async request (pendingDepositRequest / pendingRedeemRequest) and may differ from the eventual share owner — e.g. a smart wallet or router acting on a user's behalf. Example: 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"},{"schema":{"type":"string","maxLength":42,"pattern":"^0x[0-9a-fA-F]{40}$"},"in":"query","name":"vaultAddress","required":false,"description":"Filter to a specific vault address. Example: 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"},{"schema":{"type":"string","maxLength":200},"in":"query","name":"networkId","required":false,"description":"CAIP-2 network ID (e.g., \"eip155:1\", \"eip155:8453\"). If omitted, results span all chains."}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["controllerAddress","pendingDeposits","claimableDeposits"],"properties":{"controllerAddress":{"type":"string","description":"ERC-7540 controller address — the account that initiated the async deposit/redeem request. May differ from the eventual share owner."},"pendingDeposits":{"type":"array","items":{"type":"object","required":["vaultId","vaultAddress","networkId","pendingAssets"],"properties":{"vaultId":{"type":"string","format":"uuid"},"vaultAddress":{"type":"string"},"networkId":{"type":"string"},"pendingAssets":{"type":"string","description":"Pending deposit amount (raw uint256 — divide by 10^decimals to get human-readable value)"},"decimals":{"type":"integer","nullable":true},"assetToken":{"type":"string","nullable":true}}}},"claimableDeposits":{"type":"array","items":{"type":"object","required":["vaultId","vaultAddress","networkId","claimableAssets","claimableShares"],"properties":{"vaultId":{"type":"string","format":"uuid"},"vaultAddress":{"type":"string"},"networkId":{"type":"string"},"claimableAssets":{"type":"string","description":"Claimable asset amount (raw uint256 — divide by 10^decimals to get human-readable value)"},"claimableShares":{"type":"string","description":"Claimable share amount (raw uint256 — divide by 10^decimals to get human-readable value)"},"decimals":{"type":"integer","nullable":true},"assetToken":{"type":"string","nullable":true}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Get depositor pending redemptions

> Get pending redemption requests across all vaults for a given depositor controller address. If networkId is omitted, results span all chains. Requires authentication.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Depositors","description":"Depositor portfolio and performance metrics"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/depositors/pending-redemptions":{"get":{"operationId":"getDepositorPendingRedemptions","summary":"Get depositor pending redemptions","tags":["Depositors"],"description":"Get pending redemption requests across all vaults for a given depositor controller address. If networkId is omitted, results span all chains. Requires authentication.","parameters":[{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["v1","v2","v3"]}},"in":"query","name":"protocolVersion","required":false,"description":"Filter by protocol version(s). Comma-separated or repeated (e.g. `?protocolVersion=v1,v2` or `?protocolVersion=v1&protocolVersion=v2`). Omit to return all versions."},{"schema":{"type":"string","maxLength":200},"in":"query","name":"address","required":true,"description":"Depositor controller address to look up pending redemptions for. The controller is the address that initiated the ERC-7540 async request (pendingDepositRequest / pendingRedeemRequest) and may differ from the eventual share owner — e.g. a smart wallet or router acting on a user's behalf. Example: 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"},{"schema":{"type":"string","maxLength":42,"pattern":"^0x[0-9a-fA-F]{40}$"},"in":"query","name":"vaultAddress","required":false,"description":"Filter to a specific vault address. Example: 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"},{"schema":{"type":"string","maxLength":200},"in":"query","name":"networkId","required":false,"description":"CAIP-2 network ID (e.g., \"eip155:1\", \"eip155:8453\"). If omitted, results span all chains."}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["controllerAddress","pendingRedemptions","claimableRedemptions"],"properties":{"controllerAddress":{"type":"string","description":"ERC-7540 controller address — the account that initiated the async deposit/redeem request. May differ from the eventual share owner."},"pendingRedemptions":{"type":"array","items":{"type":"object","required":["vaultId","vaultAddress","networkId","pendingShares"],"properties":{"vaultId":{"type":"string","format":"uuid"},"vaultAddress":{"type":"string"},"networkId":{"type":"string"},"pendingShares":{"type":"string","description":"Pending share amount (raw uint256 — divide by 10^decimals to get human-readable value)"},"decimals":{"type":"integer","nullable":true},"shareToken":{"type":"string","nullable":true}}}},"claimableRedemptions":{"type":"array","items":{"type":"object","required":["vaultId","vaultAddress","networkId","claimableShares","claimableAssets"],"properties":{"vaultId":{"type":"string","format":"uuid"},"vaultAddress":{"type":"string"},"networkId":{"type":"string"},"claimableShares":{"type":"string","description":"Claimable share amount (raw uint256 — divide by 10^decimals to get human-readable value)"},"claimableAssets":{"type":"string","description":"Claimable asset amount (raw uint256 — divide by 10^decimals to get human-readable value)"},"decimals":{"type":"integer","nullable":true},"shareToken":{"type":"string","nullable":true}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Get depositor vault balances

> Get vault share balances for a depositor address. Returns vaults where the address holds shares, with current balance and asset value. If networkId is omitted, results span all chains. Requires authentication.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Depositors","description":"Depositor portfolio and performance metrics"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/depositors/balances":{"get":{"operationId":"getDepositorBalances","summary":"Get depositor vault balances","tags":["Depositors"],"description":"Get vault share balances for a depositor address. Returns vaults where the address holds shares, with current balance and asset value. If networkId is omitted, results span all chains. Requires authentication.","parameters":[{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["v1","v2","v3"]}},"in":"query","name":"protocolVersion","required":false,"description":"Filter by protocol version(s). Comma-separated or repeated (e.g. `?protocolVersion=v1,v2` or `?protocolVersion=v1&protocolVersion=v2`). Omit to return all versions."},{"schema":{"type":"string","maxLength":200},"in":"query","name":"address","required":true,"description":"Depositor owner address — the ERC-4626 holder of vault shares (per balanceOf). Returns balances for shares currently owned by this address. Example: 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"},{"schema":{"type":"string","maxLength":200},"in":"query","name":"networkId","required":false,"description":"CAIP-2 network ID (e.g., \"eip155:1\", \"eip155:8453\"). If omitted, results span all chains."},{"schema":{"type":"boolean"},"in":"query","name":"includeZeroBalances","required":false,"description":"If true, include vaults where the address has historical transfer activity but current balance is 0. Defaults to false."}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["address","vaults"],"properties":{"address":{"type":"string","description":"Depositor owner address queried — the ERC-4626 share holder."},"vaults":{"type":"array","items":{"type":"object","required":["vaultId","vaultAddress","networkId","shares"],"properties":{"vaultId":{"type":"string","format":"uuid","description":"Vault ID"},"vaultAddress":{"type":"string","description":"Vault contract address"},"networkId":{"type":"string","description":"CAIP-2 network ID"},"shares":{"type":"string","description":"Current share balance (raw uint256 — divide by 10^decimals to get human-readable value)"},"assetsValue":{"type":"string","nullable":true,"description":"Shares converted to underlying assets (raw uint256 — divide by 10^decimals to get human-readable value)"},"assetsValueUsd":{"type":"string","nullable":true,"description":"USD value of the depositor's vault position (null if price unavailable)"},"decimals":{"type":"integer","nullable":true,"description":"Token decimals"},"assetToken":{"type":"string","nullable":true,"description":"Underlying asset token address"}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Get depositor portfolio

> Returns a depositor's portfolio broken down by vault and aggregated at the portfolio level. Per-vault data includes: annualized yield (APY calculated as IRR/money-weighted return), holding period, interest earned, start/end position values, total deposited/withdrawn, share balances, and deposit/withdraw counts — all in both native token amounts (raw integer strings) and USD where pricing is available. The portfolio-level summary aggregates these metrics across all vaults in USD, including a combined APY. Use the expand parameter to include per-vault transaction timelines (with running balances), organization details, and daily time series (vault-daily-stats for per-vault, portfolio-daily-stats for portfolio-level, or daily-stats for both). Uses FIFO accounting for cost basis tracking. Supports optional date range filtering — when startDate is provided, all prior transactions are used to compute the opening position. Requires authentication.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Depositors","description":"Depositor portfolio and performance metrics"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"Organization":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string","format":"uuid","description":"Organization unique identifier"},"name":{"type":"string","maxLength":255,"description":"Organization display name"},"slug":{"type":"string","maxLength":100,"description":"URL-friendly identifier"},"header":{"type":"string","nullable":true,"description":"Short tagline or headline for the organization profile"},"description":{"type":"string","nullable":true,"description":"Brief summary of the organization"},"overview":{"type":"string","nullable":true,"description":"Long-form organization description (may contain Markdown)"},"links":{"type":"array","description":"Organization links and image assets. Labels starting with \"#\" are image assets (e.g. \"#logo\", \"#header\"); all others are external links (e.g. \"Twitter\", \"Website\").","items":{"type":"object","required":["id","label","url"],"properties":{"id":{"type":"string","format":"uuid","description":"Link unique identifier"},"label":{"type":"string","description":"Link type. \"#logo\" and \"#header\" denote image assets; other values (e.g. \"Twitter\", \"Website\") denote external links."},"linkText":{"type":"string","nullable":true,"description":"Display text for external links (e.g. \"@raincards\", \"rain.xyz\")"},"iconUrl":{"type":"string","nullable":true,"description":"Icon image URL for external links"},"url":{"type":"string","description":"Target URL (image URL for asset links, destination URL for external links)"}}}}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/depositors/portfolio":{"get":{"operationId":"getDepositorPortfolio","summary":"Get depositor portfolio","tags":["Depositors"],"description":"Returns a depositor's portfolio broken down by vault and aggregated at the portfolio level. Per-vault data includes: annualized yield (APY calculated as IRR/money-weighted return), holding period, interest earned, start/end position values, total deposited/withdrawn, share balances, and deposit/withdraw counts — all in both native token amounts (raw integer strings) and USD where pricing is available. The portfolio-level summary aggregates these metrics across all vaults in USD, including a combined APY. Use the expand parameter to include per-vault transaction timelines (with running balances), organization details, and daily time series (vault-daily-stats for per-vault, portfolio-daily-stats for portfolio-level, or daily-stats for both). Uses FIFO accounting for cost basis tracking. Supports optional date range filtering — when startDate is provided, all prior transactions are used to compute the opening position. Requires authentication.","parameters":[{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["v1","v2","v3"]}},"in":"query","name":"protocolVersion","required":false,"description":"Filter by protocol version(s). Comma-separated or repeated (e.g. `?protocolVersion=v1,v2` or `?protocolVersion=v1&protocolVersion=v2`). Omit to return all versions."},{"schema":{"type":"string","maxLength":200},"in":"query","name":"address","required":true,"description":"Depositor owner address — the ERC-4626 holder of vault shares (per balanceOf). Returns portfolio performance for shares currently owned by this address. Example: 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"},{"schema":{"type":"string","maxLength":200},"in":"query","name":"networkId","required":false,"description":"CAIP-2 network ID (e.g., \"eip155:1\", \"eip155:8453\"). If omitted, results span all chains."},{"schema":{"type":"string"},"in":"query","name":"startDate","required":false,"description":"ISO 8601 date for the start of the measurement window (earliest: 2020-01-01). Prior transactions are used to compute the opening position."},{"schema":{"type":"string"},"in":"query","name":"endDate","required":false,"description":"ISO 8601 date for the end of the measurement window (inclusive). Defaults to now."},{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["transactions","organization","vault-daily-stats","portfolio-daily-stats","daily-stats"]}},"in":"query","name":"expand","required":false,"description":"Comma-separated list of fields to expand. Valid values: \"transactions\" (includes per-vault transaction timelines (with running balances)), \"organization\" (includes full organization object with links for each vault), \"vault-daily-stats\" (includes per-vault daily stats timeseries), \"portfolio-daily-stats\" (includes portfolio-level daily stats timeseries (USD-denominated, summed across vaults)), \"daily-stats\" (alias — expands to both vault-daily-stats and portfolio-daily-stats)."}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["address","networkId","startDate","endDate","vaults","portfolio"],"properties":{"address":{"type":"string","description":"Depositor owner address queried — the ERC-4626 share holder."},"networkId":{"type":"string","nullable":true,"description":"CAIP-2 network filter applied (null if querying all chains)"},"startDate":{"type":"string","nullable":true,"format":"date-time","description":"Start of measurement window (resolved from param or earliest activity; null if no activity)"},"endDate":{"type":"string","nullable":true,"format":"date-time","description":"End of measurement window (resolved from param or current time; null if no activity)"},"vaults":{"type":"array","items":{"type":"object","required":["vaultId","vaultAddress","networkId","decimals","holdingPeriodDays","totalInterestEarned","startValue","endValue","totalDeposited","totalWithdrawn","startShares","endShares","depositCount","withdrawCount"],"properties":{"vaultId":{"type":"string","format":"uuid"},"vaultAddress":{"type":"string"},"networkId":{"type":"string"},"apyPct":{"type":"number","nullable":true,"description":"Annualized money-weighted return as percent (10.00 = 10%). Null if holding period < 24h."},"holdingPeriodDays":{"type":"number","description":"Holding period in days (rounded to 2 decimal places)"},"assetToken":{"type":"string","nullable":true,"description":"Underlying asset token address"},"assetTokenSymbol":{"type":"string","nullable":true,"description":"Underlying asset token symbol (e.g., USDC)"},"decimals":{"type":"integer","description":"Asset token decimals — divide raw integer values by 10^decimals for human-readable amounts. Share amounts currently use the same decimals (our vaults have ERC-4626 parity) but the spec only recommends this."},"organization":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Organization"}],"description":"Organization details with links. Only included when expand includes \"organization\"."},"totalInterestEarned":{"type":"string","description":"Total interest earned (realized + unrealized) as raw integer string — divide by 10^decimals for human-readable value"},"startValue":{"type":"string","description":"Position value at start of measurement window as raw integer string — divide by 10^decimals for human-readable value"},"endValue":{"type":"string","description":"Position value at end of measurement window as raw integer string — divide by 10^decimals for human-readable value"},"totalDeposited":{"type":"string","description":"Total deposited as raw integer string — divide by 10^decimals for human-readable value"},"totalWithdrawn":{"type":"string","description":"Total withdrawn as raw integer string — divide by 10^decimals for human-readable value"},"totalInterestEarnedUsd":{"type":"string","nullable":true,"description":"Total interest earned in USD (null if price unavailable)"},"startValueUsd":{"type":"string","nullable":true,"description":"Start value in USD (null if price unavailable)"},"endValueUsd":{"type":"string","nullable":true,"description":"End value in USD (null if price unavailable)"},"totalDepositedUsd":{"type":"string","nullable":true,"description":"Total deposited in USD (null if price unavailable)"},"totalWithdrawnUsd":{"type":"string","nullable":true,"description":"Total withdrawn in USD (null if price unavailable)"},"totalTransferredIn":{"type":"string","description":"Total transferred in via peer-to-peer share transfers as raw integer string — divide by 10^decimals for human-readable value"},"totalTransferredOut":{"type":"string","description":"Total transferred out via peer-to-peer share transfers as raw integer string — divide by 10^decimals for human-readable value"},"totalTransferredInUsd":{"type":"string","nullable":true,"description":"Total transferred in USD (null if price unavailable)"},"totalTransferredOutUsd":{"type":"string","nullable":true,"description":"Total transferred out in USD (null if price unavailable)"},"totalSharesDeposited":{"type":"string","description":"Total shares deposited as raw integer string — divide by 10^decimals for human-readable value"},"totalSharesWithdrawn":{"type":"string","description":"Total shares withdrawn as raw integer string — divide by 10^decimals for human-readable value"},"totalSharesTransferredIn":{"type":"string","description":"Total shares received via peer-to-peer transfers as raw integer string — divide by 10^decimals for human-readable value"},"totalSharesTransferredOut":{"type":"string","description":"Total shares sent via peer-to-peer transfers as raw integer string — divide by 10^decimals for human-readable value"},"startShares":{"type":"string","description":"Share balance at start of measurement window as raw integer string — divide by 10^decimals for human-readable value"},"endShares":{"type":"string","description":"Share balance at end of measurement window as raw integer string — divide by 10^decimals for human-readable value"},"depositCount":{"type":"integer"},"withdrawCount":{"type":"integer"},"transferInCount":{"type":"integer"},"transferOutCount":{"type":"integer"},"dailyStats":{"type":"array","description":"Daily timeseries with share balances, asset values, and cumulative interest. Only included when expand includes \"vault-daily-stats\" or \"daily-stats\".","items":{"type":"object","required":["date","shares"],"properties":{"date":{"type":"string","description":"UTC date (YYYY-MM-DD)"},"shares":{"type":"string","description":"Share balance at end of day as raw integer string — divide by 10^decimals for human-readable value"},"balance":{"type":"string","nullable":true,"description":"Asset value at end of day (shares × sharePrice) as raw integer string — null if no share price snapshot available"},"balanceUsd":{"type":"string","nullable":true,"description":"USD value of position at end of day (null if price unavailable)"},"totalInterestEarned":{"type":"string","nullable":true,"description":"Cumulative interest earned up to this day as raw integer string — null if balance is null"},"totalInterestEarnedUsd":{"type":"string","nullable":true,"description":"Cumulative interest earned up to this day in USD (null if price unavailable)"}}}},"transactions":{"type":"array","description":"Ordered transaction timeline (real on-chain events only)","items":{"type":"object","required":["type","timestamp","amount","amountUsd","balance","balanceUsd","shares","sharesBalance"],"properties":{"type":{"type":"string","enum":["deposit","withdraw","transfer-in","transfer-out"]},"timestamp":{"type":"string","format":"date-time"},"amount":{"type":"string","description":"Native asset amount as raw integer string — divide by 10^decimals for human-readable value."},"amountUsd":{"type":"string","nullable":true,"description":"USD amount at transaction time (null if price unavailable)"},"balance":{"type":"string","description":"Running balance (mark-to-market: sharesBalance * sharePrice) as raw integer string — divide by 10^decimals for human-readable value"},"shares":{"type":"string","description":"Share amount for this event as raw integer string — divide by 10^decimals for human-readable value."},"sharesBalance":{"type":"string","description":"Running share count after this event as raw integer string — divide by 10^decimals for human-readable value"},"balanceUsd":{"type":"string","nullable":true,"description":"Running balance in USD at transaction time (null if price unavailable)"},"txHash":{"type":"string","nullable":true,"description":"Transaction hash"}}}}}}},"portfolio":{"type":"object","required":["apyPct","holdingPeriodDays","startValueUsd","endValueUsd","totalDepositedUsd","totalWithdrawnUsd","totalInterestEarnedUsd"],"properties":{"apyPct":{"type":"number","nullable":true,"description":"Portfolio-level annualized money-weighted return as percent (10.00 = 10%). Null if holding period < 24h."},"holdingPeriodDays":{"type":"number","description":"Total days invested in at least one vault"},"startValueUsd":{"type":"string","nullable":true,"description":"Portfolio start value in USD (null if no vaults have pricing)"},"endValueUsd":{"type":"string","nullable":true,"description":"Portfolio end value in USD (null if no vaults have pricing)"},"totalDepositedUsd":{"type":"string","nullable":true,"description":"Total deposited across all vaults in USD (null if no vaults have pricing)"},"totalWithdrawnUsd":{"type":"string","nullable":true,"description":"Total withdrawn across all vaults in USD (null if no vaults have pricing)"},"totalTransferredInUsd":{"type":"string","nullable":true,"description":"Total transferred in across all vaults in USD (null if no vaults have pricing)"},"totalTransferredOutUsd":{"type":"string","nullable":true,"description":"Total transferred out across all vaults in USD (null if no vaults have pricing)"},"transferInCount":{"type":"integer","description":"Total transfer-in count across all vaults"},"transferOutCount":{"type":"integer","description":"Total transfer-out count across all vaults"},"totalInterestEarnedUsd":{"type":"string","nullable":true,"description":"Total interest earned across all vaults in USD (null if no vaults have pricing)"},"dailyStats":{"type":"array","description":"Portfolio-level daily stats timeseries (USD-denominated, summed across vaults). Only included when expand includes \"portfolio-daily-stats\" or \"daily-stats\".","items":{"type":"object","required":["date"],"properties":{"date":{"type":"string","description":"UTC date (YYYY-MM-DD)"},"balanceUsd":{"type":"string","nullable":true,"description":"Portfolio USD balance at end of day (null if no priced vaults)"},"totalInterestEarnedUsd":{"type":"string","nullable":true,"description":"Portfolio cumulative interest earned in USD up to this day (null if no priced vaults)"}}}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```


# Whitelist Requests

Vault whitelist request management

## Submit vault whitelist request

> Submit a request to be whitelisted for a private vault (requires verified status)

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Whitelist Requests","description":"Vault whitelist request management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/whitelist-requests":{"post":{"operationId":"createWhitelistRequest","summary":"Submit vault whitelist request","tags":["Whitelist Requests"],"description":"Submit a request to be whitelisted for a private vault (requires verified status)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"vaultId":{"type":"string","format":"uuid","description":"Vault ID. If provided, vaultAddress and networkId are derived from the vault. Example: 550e8400-e29b-41d4-a716-446655440000"},"vaultAddress":{"type":"string","maxLength":42,"pattern":"^0x[0-9a-fA-F]{40}$","description":"The Ethereum address of the vault (required if vaultId is not provided). Example: 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"},"networkId":{"type":"string","maxLength":50,"description":"The CAIP-2 network identifier, e.g. \"eip155:1\" (required if vaultId is not provided)"},"requestorAddress":{"type":"string","maxLength":42,"pattern":"^0x[0-9a-fA-F]{40}$","description":"Your Ethereum address to be whitelisted. Example: 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"}},"required":["requestorAddress"],"oneOf":[{"required":["vaultId"]},{"required":["vaultAddress","networkId"]}]}}}},"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["id","vaultAddress","networkId","requestorEmail","requestorAddress","status","requestedAt","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"vaultAddress":{"type":"string"},"networkId":{"type":"string"},"requestorUserId":{"type":"string","format":"uuid","nullable":true},"requestorEmail":{"type":"string"},"requestorAddress":{"type":"string"},"status":{"type":"string"},"requestedAt":{"type":"string","format":"date-time"},"approverUserId":{"type":"string","format":"uuid","nullable":true},"approverEmail":{"type":"string","nullable":true},"approverAddress":{"type":"string","nullable":true},"processedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Get my whitelist requests

> Get all whitelist requests submitted by the authenticated user

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Whitelist Requests","description":"Vault whitelist request management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/whitelist-requests/me":{"get":{"operationId":"listMyWhitelistRequests","summary":"Get my whitelist requests","tags":["Whitelist Requests"],"description":"Get all whitelist requests submitted by the authenticated user","parameters":[{"schema":{"type":"string","enum":["pending","approved","rejected"]},"in":"query","name":"status","required":false,"description":"Filter by request status"},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"vaultId","required":false,"description":"Filter by vault ID. Takes precedence over vaultAddress. Example: 550e8400-e29b-41d4-a716-446655440000"},{"schema":{"type":"string","maxLength":42,"pattern":"^0x[0-9a-fA-F]{40}$"},"in":"query","name":"vaultAddress","required":false,"description":"Filter by vault address. Example: 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"limit","required":false},{"schema":{"type":"integer","minimum":0,"default":0},"in":"query","name":"offset","required":false}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["requests","pagination"],"properties":{"requests":{"type":"array","items":{"type":"object","required":["id","vaultAddress","networkId","requestorEmail","requestorAddress","status","requestedAt","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"vaultAddress":{"type":"string"},"networkId":{"type":"string"},"requestorUserId":{"type":"string","format":"uuid","nullable":true},"requestorEmail":{"type":"string"},"requestorAddress":{"type":"string"},"status":{"type":"string"},"requestedAt":{"type":"string","format":"date-time"},"approverUserId":{"type":"string","format":"uuid","nullable":true},"approverEmail":{"type":"string","nullable":true},"approverAddress":{"type":"string","nullable":true},"processedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}},"pagination":{"type":"object","required":["total","limit","offset"],"properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Get whitelist request by ID

> Get a specific whitelist request by ID (must be owned by you)

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Whitelist Requests","description":"Vault whitelist request management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/whitelist-requests/{requestId}":{"get":{"operationId":"getWhitelistRequest","summary":"Get whitelist request by ID","tags":["Whitelist Requests"],"description":"Get a specific whitelist request by ID (must be owned by you)","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"requestId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["id","vaultAddress","networkId","requestorEmail","requestorAddress","status","requestedAt","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"vaultAddress":{"type":"string"},"networkId":{"type":"string"},"requestorUserId":{"type":"string","format":"uuid","nullable":true},"requestorEmail":{"type":"string"},"requestorAddress":{"type":"string"},"status":{"type":"string"},"requestedAt":{"type":"string","format":"date-time"},"approverUserId":{"type":"string","format":"uuid","nullable":true},"approverEmail":{"type":"string","nullable":true},"approverAddress":{"type":"string","nullable":true},"processedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Get whitelist requests for a vault

> Get all whitelist requests for a specific vault by vault ID. Requires the caller to be a member of the vault's organization.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Whitelist Requests","description":"Vault whitelist request management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/whitelist-requests/vault/{vaultId}":{"get":{"operationId":"listVaultWhitelistRequests","summary":"Get whitelist requests for a vault","tags":["Whitelist Requests"],"description":"Get all whitelist requests for a specific vault by vault ID. Requires the caller to be a member of the vault's organization.","parameters":[{"schema":{"type":"string","enum":["pending","approved","rejected"]},"in":"query","name":"status","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"vaultId","required":true,"description":"Vault ID. Example: 550e8400-e29b-41d4-a716-446655440000"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["requests","total"],"properties":{"requests":{"type":"array","items":{"type":"object","required":["id","vaultAddress","networkId","requestorEmail","requestorAddress","status","requestedAt","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"vaultAddress":{"type":"string"},"networkId":{"type":"string"},"requestorUserId":{"type":"string","format":"uuid","nullable":true},"requestorEmail":{"type":"string"},"requestorAddress":{"type":"string"},"status":{"type":"string"},"requestedAt":{"type":"string","format":"date-time"},"approverUserId":{"type":"string","format":"uuid","nullable":true},"approverEmail":{"type":"string","nullable":true},"approverAddress":{"type":"string","nullable":true},"processedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}},"total":{"type":"integer"}}}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Reject a whitelist request

> Reject a whitelist request. Requires the caller to be a curator in the vault's organization.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Whitelist Requests","description":"Vault whitelist request management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/whitelist-requests/{requestId}/reject":{"post":{"operationId":"rejectWhitelistRequest","summary":"Reject a whitelist request","tags":["Whitelist Requests"],"description":"Reject a whitelist request. Requires the caller to be a curator in the vault's organization.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"approverAddress":{"type":"string","maxLength":42,"pattern":"^0x[0-9a-fA-F]{40}$","description":"Optional Ethereum address of the approver. Example: 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"requestId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["id","vaultAddress","networkId","requestorEmail","requestorAddress","status","requestedAt","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"vaultAddress":{"type":"string"},"networkId":{"type":"string"},"requestorUserId":{"type":"string","format":"uuid","nullable":true},"requestorEmail":{"type":"string"},"requestorAddress":{"type":"string"},"status":{"type":"string"},"requestedAt":{"type":"string","format":"date-time"},"approverUserId":{"type":"string","format":"uuid","nullable":true},"approverEmail":{"type":"string","nullable":true},"approverAddress":{"type":"string","nullable":true},"processedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```


# Ledger

Typed ledger endpoints: transfers, borrows, repays, cumulative cashflows

## List credit facility borrow events

> Get on-chain borrow events for an organization. Each row represents a single \`Borrow\` event emitted by a SecuredLine credit facility — the moment outstanding principal was drawn against the line.\
> \
> Results are sorted by \`occurredAt\` (descending — newest first). Ordering is not configurable from the query string.\
> \
> Supports three response formats via the \`format\` query parameter:\
> \- \*\*json\*\* (default) — paginated JSON (default limit 100, max 1000).\
> \- \*\*csv\*\* — streamed CSV file download (up to 1,000,000 rows). Columns: inflow, transaction, type, timestamp, amount, usdValue, tokenAddress, tokenIcon, tokenSymbol.\
> \- \*\*event-stream\*\* — Server-Sent Events stream (up to 1,000,000 rows). Each entry is emitted as a named \`entry\` event with JSON data. A final \`done\` event carries \`{"total": N}\`. Connect with \`EventSource\` or \`fetch\`:\
> \
> \`\`\`js\
> const es = new EventSource('/v3/ledger/borrows?organizationId={id}\&format=event-stream', {\
> &#x20; headers: { 'x-api-key': 'cc\_...' },\
> });\
> es.addEventListener('entry', (e) => console.log(JSON.parse(e.data)));\
> es.addEventListener('done', (e) => { console.log('total:', JSON.parse(e.data).total); es.close(); });\
> \`\`\`\
> \
> Requires org membership or vault curator role (public orgs only).

````json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Ledger","description":"Typed ledger endpoints: transfers, borrows, repays, cumulative cashflows"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"Pagination":{"type":"object","required":["total","limit","offset"],"properties":{"total":{"type":"integer","description":"Total number of records matching the query"},"limit":{"type":"integer","description":"Maximum number of records returned per page"},"offset":{"type":"integer","description":"Number of records skipped from the start"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/ledger/borrows":{"get":{"operationId":"listBorrows","summary":"List credit facility borrow events","tags":["Ledger"],"description":"Get on-chain borrow events for an organization. Each row represents a single `Borrow` event emitted by a SecuredLine credit facility — the moment outstanding principal was drawn against the line.\n\nResults are sorted by `occurredAt` (descending — newest first). Ordering is not configurable from the query string.\n\nSupports three response formats via the `format` query parameter:\n- **json** (default) — paginated JSON (default limit 100, max 1000).\n- **csv** — streamed CSV file download (up to 1,000,000 rows). Columns: inflow, transaction, type, timestamp, amount, usdValue, tokenAddress, tokenIcon, tokenSymbol.\n- **event-stream** — Server-Sent Events stream (up to 1,000,000 rows). Each entry is emitted as a named `entry` event with JSON data. A final `done` event carries `{\"total\": N}`. Connect with `EventSource` or `fetch`:\n\n```js\nconst es = new EventSource('/v3/ledger/borrows?organizationId={id}&format=event-stream', {\n  headers: { 'x-api-key': 'cc_...' },\n});\nes.addEventListener('entry', (e) => console.log(JSON.parse(e.data)));\nes.addEventListener('done', (e) => { console.log('total:', JSON.parse(e.data).total); es.close(); });\n```\n\nRequires org membership or vault curator role (public orgs only).","parameters":[{"schema":{"type":"string","format":"uuid","maxLength":36},"in":"query","name":"organizationId","required":true,"description":"Organization ID (must be an org the caller is a member of, or a public org if caller is a vault curator)."},{"schema":{"type":"string","format":"date"},"in":"query","name":"startDate","required":false,"description":"Optional filter. Inclusive start date (YYYY-MM-DD); restricts results to `occurredAt >= startDate` (or `snapshotDate` for collateral-snapshots). Omit to leave the start unbounded."},{"schema":{"type":"string","format":"date"},"in":"query","name":"endDate","required":false,"description":"Optional filter. Inclusive end date (YYYY-MM-DD). Omit to leave the end unbounded."},{"schema":{"type":"integer","minimum":1},"in":"query","name":"limit","required":false,"description":"Maximum records returned. Format-dependent: `format=json` capped at 1000 (default 100); `format=csv|event-stream` capped at 1,000,000 (default 1,000,000). Values outside these caps are silently clamped server-side."},{"schema":{"type":"integer","minimum":0,"default":0},"in":"query","name":"offset","required":false,"description":"Number of records to skip from the start (JSON pagination only — ignored for csv/event-stream)."},{"schema":{"type":"string","enum":["json","csv","event-stream"],"default":"json"},"in":"query","name":"format","required":false,"description":"Response format. `json` returns paginated JSON. `csv` streams a CSV file download. `event-stream` returns Server-Sent Events: each row is a named `entry` event; a final `done` event carries `{\"total\": N}`."},{"schema":{"type":"string","maxLength":50},"in":"query","name":"networkId","required":false,"description":"Optional filter. CAIP-2 network identifier; restricts results to a single chain. Omit to return all networks."},{"schema":{"type":"string","maxLength":42,"pattern":"^0x[0-9a-fA-F]{40}$"},"in":"query","name":"facilityAddress","required":false,"description":"Optional filter. Credit facility (SecuredLine) contract address; restricts results to a single facility. Omit to return all facilities for the organization."},{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["v1","v2","v3"]}},"in":"query","name":"protocolVersion","required":false,"description":"Filter by protocol version(s). Comma-separated or repeated (e.g. `?protocolVersion=v1,v2` or `?protocolVersion=v1&protocolVersion=v2`). Omit to return all versions."}],"responses":{"200":{"description":"Credit facility borrow events.","content":{"application/json":{"schema":{"type":"object","required":["entries","pagination"],"properties":{"entries":{"type":"array","items":{"type":"object","required":["id","organizationId","evmLogId","facilityAddress","amount","currency","occurredAt","dataSource","networkId","transactionHash","logIndex","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"organizationId":{"type":"string","format":"uuid"},"evmLogId":{"type":"string","format":"uuid"},"facilityAddress":{"type":"string","maxLength":42,"pattern":"^0x[0-9a-fA-F]{40}$","description":"Credit facility (SecuredLine) contract address."},"amount":{"type":"string","description":"Token amount with full decimal precision. Returned as a string to avoid floating-point precision loss."},"amountUsd":{"type":"string","nullable":true,"description":"USD value at time of entry. Returned as a string. May be `null` when no historical price is available for the currency."},"currency":{"type":"string","description":"Token symbol stored verbatim from source."},"occurredAt":{"type":"string","format":"date-time"},"dataSource":{"type":"string","description":"Origin of the data, e.g. `blockchain:ethereum`, `blockchain:base`."},"networkId":{"type":"string","description":"CAIP-2 network identifier."},"transactionHash":{"type":"string","description":"0x-prefixed transaction hash."},"logIndex":{"type":"integer","description":"Position of the log within the transaction."},"createdAt":{"type":"string","format":"date-time"},"organizationName":{"type":"string","nullable":true,"description":"Display name of the owning organization."},"organizationSlug":{"type":"string","nullable":true,"description":"URL-safe slug of the owning organization."}}}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}},"text/csv":{"schema":{"type":"string","description":"CSV file download. Columns: inflow, transaction, type, timestamp, amount, usdValue, tokenAddress, tokenIcon, tokenSymbol."}},"text/event-stream":{"schema":{"type":"string","description":"SSE stream. Named `entry` events carry one row each; a final `done` event carries `{\"total\": N}`."}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
````

## List credit facility repayment events

> Get on-chain repayment events for an organization. Each row represents a \`RepayPrincipal\` or \`RepayInterest\` event emitted by a SecuredLine credit facility. Filter by \`repaymentType\` to restrict to one subtype.\
> \
> Results are sorted by \`occurredAt\` (descending — newest first). Ordering is not configurable from the query string.\
> \
> Supports three response formats via the \`format\` query parameter:\
> \- \*\*json\*\* (default) — paginated JSON (default limit 100, max 1000).\
> \- \*\*csv\*\* — streamed CSV file download (up to 1,000,000 rows). Columns: inflow, transaction, type, timestamp, amount, usdValue, tokenAddress, tokenIcon, tokenSymbol.\
> \- \*\*event-stream\*\* — Server-Sent Events stream (up to 1,000,000 rows). Each entry is emitted as a named \`entry\` event with JSON data. A final \`done\` event carries \`{"total": N}\`. Connect with \`EventSource\` or \`fetch\`:\
> \
> \`\`\`js\
> const es = new EventSource('/v3/ledger/repays?organizationId={id}\&format=event-stream', {\
> &#x20; headers: { 'x-api-key': 'cc\_...' },\
> });\
> es.addEventListener('entry', (e) => console.log(JSON.parse(e.data)));\
> es.addEventListener('done', (e) => { console.log('total:', JSON.parse(e.data).total); es.close(); });\
> \`\`\`\
> \
> Requires org membership or vault curator role (public orgs only).

````json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Ledger","description":"Typed ledger endpoints: transfers, borrows, repays, cumulative cashflows"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"Pagination":{"type":"object","required":["total","limit","offset"],"properties":{"total":{"type":"integer","description":"Total number of records matching the query"},"limit":{"type":"integer","description":"Maximum number of records returned per page"},"offset":{"type":"integer","description":"Number of records skipped from the start"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/ledger/repays":{"get":{"operationId":"listRepays","summary":"List credit facility repayment events","tags":["Ledger"],"description":"Get on-chain repayment events for an organization. Each row represents a `RepayPrincipal` or `RepayInterest` event emitted by a SecuredLine credit facility. Filter by `repaymentType` to restrict to one subtype.\n\nResults are sorted by `occurredAt` (descending — newest first). Ordering is not configurable from the query string.\n\nSupports three response formats via the `format` query parameter:\n- **json** (default) — paginated JSON (default limit 100, max 1000).\n- **csv** — streamed CSV file download (up to 1,000,000 rows). Columns: inflow, transaction, type, timestamp, amount, usdValue, tokenAddress, tokenIcon, tokenSymbol.\n- **event-stream** — Server-Sent Events stream (up to 1,000,000 rows). Each entry is emitted as a named `entry` event with JSON data. A final `done` event carries `{\"total\": N}`. Connect with `EventSource` or `fetch`:\n\n```js\nconst es = new EventSource('/v3/ledger/repays?organizationId={id}&format=event-stream', {\n  headers: { 'x-api-key': 'cc_...' },\n});\nes.addEventListener('entry', (e) => console.log(JSON.parse(e.data)));\nes.addEventListener('done', (e) => { console.log('total:', JSON.parse(e.data).total); es.close(); });\n```\n\nRequires org membership or vault curator role (public orgs only).","parameters":[{"schema":{"type":"string","format":"uuid","maxLength":36},"in":"query","name":"organizationId","required":true,"description":"Organization ID (must be an org the caller is a member of, or a public org if caller is a vault curator)."},{"schema":{"type":"string","format":"date"},"in":"query","name":"startDate","required":false,"description":"Optional filter. Inclusive start date (YYYY-MM-DD); restricts results to `occurredAt >= startDate` (or `snapshotDate` for collateral-snapshots). Omit to leave the start unbounded."},{"schema":{"type":"string","format":"date"},"in":"query","name":"endDate","required":false,"description":"Optional filter. Inclusive end date (YYYY-MM-DD). Omit to leave the end unbounded."},{"schema":{"type":"integer","minimum":1},"in":"query","name":"limit","required":false,"description":"Maximum records returned. Format-dependent: `format=json` capped at 1000 (default 100); `format=csv|event-stream` capped at 1,000,000 (default 1,000,000). Values outside these caps are silently clamped server-side."},{"schema":{"type":"integer","minimum":0,"default":0},"in":"query","name":"offset","required":false,"description":"Number of records to skip from the start (JSON pagination only — ignored for csv/event-stream)."},{"schema":{"type":"string","enum":["json","csv","event-stream"],"default":"json"},"in":"query","name":"format","required":false,"description":"Response format. `json` returns paginated JSON. `csv` streams a CSV file download. `event-stream` returns Server-Sent Events: each row is a named `entry` event; a final `done` event carries `{\"total\": N}`."},{"schema":{"type":"string","enum":["principal","interest"]},"in":"query","name":"repaymentType","required":false,"description":"Optional filter. Restricts results to a single repayment subtype: `principal` (reduces outstanding principal) or `interest` (paid to depositors). Omit to return both."},{"schema":{"type":"string","maxLength":50},"in":"query","name":"networkId","required":false,"description":"Optional filter. CAIP-2 network identifier; restricts results to a single chain. Omit to return all networks."},{"schema":{"type":"string","maxLength":42,"pattern":"^0x[0-9a-fA-F]{40}$"},"in":"query","name":"facilityAddress","required":false,"description":"Optional filter. Credit facility (SecuredLine) contract address; restricts results to a single facility. Omit to return all facilities for the organization."},{"schema":{"type":"array","style":"form","explode":false,"items":{"type":"string","enum":["v1","v2","v3"]}},"in":"query","name":"protocolVersion","required":false,"description":"Filter by protocol version(s). Comma-separated or repeated (e.g. `?protocolVersion=v1,v2` or `?protocolVersion=v1&protocolVersion=v2`). Omit to return all versions."}],"responses":{"200":{"description":"Credit facility repayment events.","content":{"application/json":{"schema":{"type":"object","required":["entries","pagination"],"properties":{"entries":{"type":"array","items":{"type":"object","required":["id","organizationId","evmLogId","repaymentType","facilityAddress","amount","currency","occurredAt","dataSource","networkId","transactionHash","logIndex","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"organizationId":{"type":"string","format":"uuid"},"evmLogId":{"type":"string","format":"uuid"},"repaymentType":{"type":"string","enum":["principal","interest"],"description":"Repayment subtype: `principal` reduces outstanding principal; `interest` is paid to depositors."},"facilityAddress":{"type":"string","maxLength":42,"pattern":"^0x[0-9a-fA-F]{40}$","description":"Credit facility (SecuredLine) contract address."},"amount":{"type":"string","description":"Token amount with full decimal precision. Returned as a string to avoid floating-point precision loss."},"amountUsd":{"type":"string","nullable":true,"description":"USD value at time of entry. Returned as a string. May be `null` when no historical price is available for the currency."},"currency":{"type":"string"},"occurredAt":{"type":"string","format":"date-time"},"dataSource":{"type":"string"},"networkId":{"type":"string"},"transactionHash":{"type":"string"},"logIndex":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"organizationName":{"type":"string","nullable":true,"description":"Display name of the owning organization."},"organizationSlug":{"type":"string","nullable":true,"description":"URL-safe slug of the owning organization."}}}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}},"text/csv":{"schema":{"type":"string","description":"CSV file download. Columns: inflow, transaction, type, timestamp, amount, usdValue, tokenAddress, tokenIcon, tokenSymbol."}},"text/event-stream":{"schema":{"type":"string","description":"SSE stream. Named `entry` events carry one row each; a final `done` event carries `{\"total\": N}`."}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
````

## List individual cashflow transfer events

> Get individual cashflow transfer events for an organization. Each row is a single movement of value (on-chain \`Transfer\`, off-chain wire/ACH, swap leg, etc.) classified by stage (\`external\` → \`in\_transit\` → \`secured\` → \`settled\`) and direction (inflow / outflow). Set \`excludeLinkedTransfers=true\` to drop transfers whose tx hash matches a known borrow/repay and avoid double-counting against \`/v3/ledger/borrows\` and \`/v3/ledger/repays\`.\
> \
> Results are sorted by \`occurredAt\` (descending — newest first). Ordering is not configurable from the query string.\
> \
> Supports three response formats via the \`format\` query parameter:\
> \- \*\*json\*\* (default) — paginated JSON (default limit 100, max 1000).\
> \- \*\*csv\*\* — streamed CSV file download (up to 1,000,000 rows). Columns: inflow, transaction, type, timestamp, amount, usdValue, tokenAddress, tokenIcon, tokenSymbol.\
> \- \*\*event-stream\*\* — Server-Sent Events stream (up to 1,000,000 rows). Each entry is emitted as a named \`entry\` event with JSON data. A final \`done\` event carries \`{"total": N}\`. Connect with \`EventSource\` or \`fetch\`:\
> \
> \`\`\`js\
> const es = new EventSource('/v3/ledger/transfers?organizationId={id}\&format=event-stream', {\
> &#x20; headers: { 'x-api-key': 'cc\_...' },\
> });\
> es.addEventListener('entry', (e) => console.log(JSON.parse(e.data)));\
> es.addEventListener('done', (e) => { console.log('total:', JSON.parse(e.data).total); es.close(); });\
> \`\`\`\
> \
> Requires org membership or vault curator role (public orgs only).

````json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Ledger","description":"Typed ledger endpoints: transfers, borrows, repays, cumulative cashflows"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"Pagination":{"type":"object","required":["total","limit","offset"],"properties":{"total":{"type":"integer","description":"Total number of records matching the query"},"limit":{"type":"integer","description":"Maximum number of records returned per page"},"offset":{"type":"integer","description":"Number of records skipped from the start"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/ledger/transfers":{"get":{"operationId":"listCashflowTransfers","summary":"List individual cashflow transfer events","tags":["Ledger"],"description":"Get individual cashflow transfer events for an organization. Each row is a single movement of value (on-chain `Transfer`, off-chain wire/ACH, swap leg, etc.) classified by stage (`external` → `in_transit` → `secured` → `settled`) and direction (inflow / outflow). Set `excludeLinkedTransfers=true` to drop transfers whose tx hash matches a known borrow/repay and avoid double-counting against `/v3/ledger/borrows` and `/v3/ledger/repays`.\n\nResults are sorted by `occurredAt` (descending — newest first). Ordering is not configurable from the query string.\n\nSupports three response formats via the `format` query parameter:\n- **json** (default) — paginated JSON (default limit 100, max 1000).\n- **csv** — streamed CSV file download (up to 1,000,000 rows). Columns: inflow, transaction, type, timestamp, amount, usdValue, tokenAddress, tokenIcon, tokenSymbol.\n- **event-stream** — Server-Sent Events stream (up to 1,000,000 rows). Each entry is emitted as a named `entry` event with JSON data. A final `done` event carries `{\"total\": N}`. Connect with `EventSource` or `fetch`:\n\n```js\nconst es = new EventSource('/v3/ledger/transfers?organizationId={id}&format=event-stream', {\n  headers: { 'x-api-key': 'cc_...' },\n});\nes.addEventListener('entry', (e) => console.log(JSON.parse(e.data)));\nes.addEventListener('done', (e) => { console.log('total:', JSON.parse(e.data).total); es.close(); });\n```\n\nRequires org membership or vault curator role (public orgs only).","parameters":[{"schema":{"type":"string","format":"uuid","maxLength":36},"in":"query","name":"organizationId","required":true,"description":"Organization ID (must be an org the caller is a member of, or a public org if caller is a vault curator)."},{"schema":{"type":"string","format":"date"},"in":"query","name":"startDate","required":false,"description":"Optional filter. Inclusive start date (YYYY-MM-DD); restricts results to `occurredAt >= startDate` (or `snapshotDate` for collateral-snapshots). Omit to leave the start unbounded."},{"schema":{"type":"string","format":"date"},"in":"query","name":"endDate","required":false,"description":"Optional filter. Inclusive end date (YYYY-MM-DD). Omit to leave the end unbounded."},{"schema":{"type":"integer","minimum":1},"in":"query","name":"limit","required":false,"description":"Maximum records returned. Format-dependent: `format=json` capped at 1000 (default 100); `format=csv|event-stream` capped at 1,000,000 (default 1,000,000). Values outside these caps are silently clamped server-side."},{"schema":{"type":"integer","minimum":0,"default":0},"in":"query","name":"offset","required":false,"description":"Number of records to skip from the start (JSON pagination only — ignored for csv/event-stream)."},{"schema":{"type":"string","enum":["json","csv","event-stream"],"default":"json"},"in":"query","name":"format","required":false,"description":"Response format. `json` returns paginated JSON. `csv` streams a CSV file download. `event-stream` returns Server-Sent Events: each row is a named `entry` event; a final `done` event carries `{\"total\": N}`."},{"schema":{"type":"string","maxLength":50},"in":"query","name":"networkId","required":false,"description":"Optional filter. CAIP-2 network identifier; restricts results to a single chain. Omit to return all networks."},{"schema":{"type":"string","maxLength":255},"in":"query","name":"accountId","required":false,"description":"Optional filter. Wallet address (on-chain) or bank account identifier (off-chain); restricts results to a single account. Omit to return all accounts."},{"schema":{"type":"string","enum":["external","in_transit","secured","settled"]},"in":"query","name":"stage","required":false,"description":"Optional filter. Cash-flow stage (`external` → `in_transit` → `secured` → `settled`); restricts results to a single stage. Omit to return all stages."},{"schema":{"type":"string","maxLength":20},"in":"query","name":"type","required":false,"description":"Optional filter. Transfer mechanism; restricts results to a single mechanism (common values: `swap`, `bridge`, `onramp`, `wire`, `ach`, `direct`). Omit to return all mechanisms."},{"schema":{"type":"boolean"},"in":"query","name":"inflow","required":false,"description":"Optional filter. `true` = arriving only, `false` = leaving only. Omit to return both directions."},{"schema":{"type":"boolean","default":false},"in":"query","name":"excludeLinkedTransfers","required":false,"description":"Optional. When `true`, excludes transfers whose tx hash matches a known borrow/repay event, to avoid double-counting with /v3/ledger/borrows and /v3/ledger/repays. Defaults to `false`."}],"responses":{"200":{"description":"Individual cashflow transfer events.","content":{"application/json":{"schema":{"type":"object","required":["entries","pagination"],"properties":{"entries":{"type":"array","items":{"type":"object","required":["id","organizationId","inflow","stage","accountId","amount","currency","occurredAt","dataSource","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"organizationId":{"type":"string","format":"uuid"},"webCaptureId":{"type":"string","format":"uuid","nullable":true},"evmLogId":{"type":"string","format":"uuid","nullable":true},"inflow":{"type":"boolean","description":"true = arriving, false = leaving."},"stage":{"type":"string","enum":["external","in_transit","secured","settled"],"description":"Cash-flow stage at time of capture (`external` → `in_transit` → `secured` → `settled`)."},"type":{"type":"string","nullable":true,"description":"Transfer mechanism (common values: `swap`, `bridge`, `onramp`, `wire`, `ach`, `direct`)."},"accountId":{"type":"string","description":"Wallet address (on-chain) or bank account identifier (off-chain)."},"institutionId":{"type":"string","nullable":true,"description":"Source institution that reported this transfer (e.g. `self_report`, `visa`)."},"externalTransactionId":{"type":"string","nullable":true,"description":"Source-system identifier for the transaction."},"amount":{"type":"string","description":"Token amount with full decimal precision. Returned as a string to avoid floating-point precision loss."},"amountUsd":{"type":"string","nullable":true,"description":"USD value at time of entry. Returned as a string. May be `null` when no historical price is available for the currency."},"currency":{"type":"string"},"occurredAt":{"type":"string","format":"date-time"},"dataSource":{"type":"string"},"networkId":{"type":"string","nullable":true},"transactionHash":{"type":"string","nullable":true},"logIndex":{"type":"integer","nullable":true},"createdAt":{"type":"string","format":"date-time"},"organizationName":{"type":"string","nullable":true,"description":"Display name of the owning organization."},"organizationSlug":{"type":"string","nullable":true,"description":"URL-safe slug of the owning organization."}}}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}},"text/csv":{"schema":{"type":"string","description":"CSV file download. Columns: inflow, transaction, type, timestamp, amount, usdValue, tokenAddress, tokenIcon, tokenSymbol."}},"text/event-stream":{"schema":{"type":"string","description":"SSE stream. Named `entry` events carry one row each; a final `done` event carries `{\"total\": N}`."}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
````

## List aggregate daily cashflow snapshots

> Get daily aggregate cashflow snapshots reported by an institution (e.g. \`self\_report\`, \`visa\`) on behalf of an organization. Unlike \`/v3/ledger/transfers\`, each row is a \*period summary\* — typically one row per (institution, day, direction) — not an individual transaction. Use this endpoint when you want pre-aggregated totals; use \`/v3/ledger/transfers\` for line-item activity.\
> \
> Results are sorted by \`occurredAt\` (descending — newest first). Ordering is not configurable from the query string.\
> \
> Supports three response formats via the \`format\` query parameter:\
> \- \*\*json\*\* (default) — paginated JSON (default limit 100, max 1000).\
> \- \*\*csv\*\* — streamed CSV file download (up to 1,000,000 rows). Columns: inflow, transaction, type, timestamp, amount, usdValue, tokenAddress, tokenIcon, tokenSymbol.\
> \- \*\*event-stream\*\* — Server-Sent Events stream (up to 1,000,000 rows). Each entry is emitted as a named \`entry\` event with JSON data. A final \`done\` event carries \`{"total": N}\`. Connect with \`EventSource\` or \`fetch\`:\
> \
> \`\`\`js\
> const es = new EventSource('/v3/ledger/cumulative-cashflows?organizationId={id}\&format=event-stream', {\
> &#x20; headers: { 'x-api-key': 'cc\_...' },\
> });\
> es.addEventListener('entry', (e) => console.log(JSON.parse(e.data)));\
> es.addEventListener('done', (e) => { console.log('total:', JSON.parse(e.data).total); es.close(); });\
> \`\`\`\
> \
> Requires org membership or vault curator role (public orgs only).

````json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Ledger","description":"Typed ledger endpoints: transfers, borrows, repays, cumulative cashflows"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"Pagination":{"type":"object","required":["total","limit","offset"],"properties":{"total":{"type":"integer","description":"Total number of records matching the query"},"limit":{"type":"integer","description":"Maximum number of records returned per page"},"offset":{"type":"integer","description":"Number of records skipped from the start"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/ledger/cumulative-cashflows":{"get":{"operationId":"listCumulativeCashflows","summary":"List aggregate daily cashflow snapshots","tags":["Ledger"],"description":"Get daily aggregate cashflow snapshots reported by an institution (e.g. `self_report`, `visa`) on behalf of an organization. Unlike `/v3/ledger/transfers`, each row is a *period summary* — typically one row per (institution, day, direction) — not an individual transaction. Use this endpoint when you want pre-aggregated totals; use `/v3/ledger/transfers` for line-item activity.\n\nResults are sorted by `occurredAt` (descending — newest first). Ordering is not configurable from the query string.\n\nSupports three response formats via the `format` query parameter:\n- **json** (default) — paginated JSON (default limit 100, max 1000).\n- **csv** — streamed CSV file download (up to 1,000,000 rows). Columns: inflow, transaction, type, timestamp, amount, usdValue, tokenAddress, tokenIcon, tokenSymbol.\n- **event-stream** — Server-Sent Events stream (up to 1,000,000 rows). Each entry is emitted as a named `entry` event with JSON data. A final `done` event carries `{\"total\": N}`. Connect with `EventSource` or `fetch`:\n\n```js\nconst es = new EventSource('/v3/ledger/cumulative-cashflows?organizationId={id}&format=event-stream', {\n  headers: { 'x-api-key': 'cc_...' },\n});\nes.addEventListener('entry', (e) => console.log(JSON.parse(e.data)));\nes.addEventListener('done', (e) => { console.log('total:', JSON.parse(e.data).total); es.close(); });\n```\n\nRequires org membership or vault curator role (public orgs only).","parameters":[{"schema":{"type":"string","format":"uuid","maxLength":36},"in":"query","name":"organizationId","required":true,"description":"Organization ID (must be an org the caller is a member of, or a public org if caller is a vault curator)."},{"schema":{"type":"string","format":"date"},"in":"query","name":"startDate","required":false,"description":"Optional filter. Inclusive start date (YYYY-MM-DD); restricts results to `occurredAt >= startDate` (or `snapshotDate` for collateral-snapshots). Omit to leave the start unbounded."},{"schema":{"type":"string","format":"date"},"in":"query","name":"endDate","required":false,"description":"Optional filter. Inclusive end date (YYYY-MM-DD). Omit to leave the end unbounded."},{"schema":{"type":"integer","minimum":1},"in":"query","name":"limit","required":false,"description":"Maximum records returned. Format-dependent: `format=json` capped at 1000 (default 100); `format=csv|event-stream` capped at 1,000,000 (default 1,000,000). Values outside these caps are silently clamped server-side."},{"schema":{"type":"integer","minimum":0,"default":0},"in":"query","name":"offset","required":false,"description":"Number of records to skip from the start (JSON pagination only — ignored for csv/event-stream)."},{"schema":{"type":"string","enum":["json","csv","event-stream"],"default":"json"},"in":"query","name":"format","required":false,"description":"Response format. `json` returns paginated JSON. `csv` streams a CSV file download. `event-stream` returns Server-Sent Events: each row is a named `entry` event; a final `done` event carries `{\"total\": N}`."},{"schema":{"type":"string","maxLength":100},"in":"query","name":"institutionId","required":false,"description":"Optional filter. Source institution that reported the aggregate (e.g. `self_report`, `visa`); restricts results to a single institution. Omit to return all institutions."},{"schema":{"type":"string","enum":["external","in_transit","secured","settled"]},"in":"query","name":"stage","required":false,"description":"Optional filter. Cash-flow stage (`external` → `in_transit` → `secured` → `settled`); restricts results to a single stage. Omit to return all stages."},{"schema":{"type":"boolean"},"in":"query","name":"inflow","required":false,"description":"Optional filter. `true` = arriving only, `false` = leaving only. Omit to return both directions."}],"responses":{"200":{"description":"Aggregate daily cashflow snapshots.","content":{"application/json":{"schema":{"type":"object","required":["entries","pagination"],"properties":{"entries":{"type":"array","items":{"type":"object","required":["id","organizationId","webCaptureId","inflow","stage","institutionId","externalTransactionId","amount","currency","occurredAt","dataSource","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"organizationId":{"type":"string","format":"uuid"},"webCaptureId":{"type":"string","format":"uuid"},"inflow":{"type":"boolean"},"stage":{"type":"string","enum":["external","in_transit","secured","settled"],"description":"Cash-flow stage at time of capture (`external` → `in_transit` → `secured` → `settled`)."},"accountId":{"type":"string","nullable":true},"institutionId":{"type":"string","description":"Source institution that reported this aggregate (e.g. `self_report`, `visa`)."},"externalTransactionId":{"type":"string","description":"Source-system identifier for the aggregate."},"amount":{"type":"string","description":"Token amount with full decimal precision. Returned as a string to avoid floating-point precision loss."},"amountUsd":{"type":"string","nullable":true,"description":"USD value at time of entry. Returned as a string. May be `null` when no historical price is available for the currency."},"currency":{"type":"string"},"occurredAt":{"type":"string","format":"date-time"},"dataSource":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"organizationName":{"type":"string","nullable":true,"description":"Display name of the owning organization."},"organizationSlug":{"type":"string","nullable":true,"description":"URL-safe slug of the owning organization."}}}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}},"text/csv":{"schema":{"type":"string","description":"CSV file download. Columns: inflow, transaction, type, timestamp, amount, usdValue, tokenAddress, tokenIcon, tokenSymbol."}},"text/event-stream":{"schema":{"type":"string","description":"SSE stream. Named `entry` events carry one row each; a final `done` event carries `{\"total\": N}`."}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
````

## List point-in-time collateral USD snapshots

> Get daily collateral USD snapshots for an organization. Each row is the total USD value of collateral held on a given calendar day — one row per organization per day. Use this for time-series collateral charts and coverage ratios; combine with \`/v3/ledger/borrows\` + \`/v3/ledger/repays\` to compute net leverage over time.\
> \
> Results are sorted by \`snapshotDate\` (descending — newest first). Ordering is not configurable from the query string.\
> \
> Supports three response formats via the \`format\` query parameter:\
> \- \*\*json\*\* (default) — paginated JSON (default limit 100, max 1000).\
> \- \*\*csv\*\* — streamed CSV file download (up to 1,000,000 rows). Columns: snapshotDate, amountUsd, organizationId, organizationName, createdAt.\
> \- \*\*event-stream\*\* — Server-Sent Events stream (up to 1,000,000 rows). Each entry is emitted as a named \`entry\` event with JSON data. A final \`done\` event carries \`{"total": N}\`. Connect with \`EventSource\` or \`fetch\`:\
> \
> \`\`\`js\
> const es = new EventSource('/v3/ledger/cumulative-collateral?organizationId={id}\&format=event-stream', {\
> &#x20; headers: { 'x-api-key': 'cc\_...' },\
> });\
> es.addEventListener('entry', (e) => console.log(JSON.parse(e.data)));\
> es.addEventListener('done', (e) => { console.log('total:', JSON.parse(e.data).total); es.close(); });\
> \`\`\`\
> \
> Requires org membership or vault curator role (public orgs only).

````json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Ledger","description":"Typed ledger endpoints: transfers, borrows, repays, cumulative cashflows"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"Pagination":{"type":"object","required":["total","limit","offset"],"properties":{"total":{"type":"integer","description":"Total number of records matching the query"},"limit":{"type":"integer","description":"Maximum number of records returned per page"},"offset":{"type":"integer","description":"Number of records skipped from the start"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/ledger/cumulative-collateral":{"get":{"operationId":"listCumulativeCollateral","summary":"List point-in-time collateral USD snapshots","tags":["Ledger"],"description":"Get daily collateral USD snapshots for an organization. Each row is the total USD value of collateral held on a given calendar day — one row per organization per day. Use this for time-series collateral charts and coverage ratios; combine with `/v3/ledger/borrows` + `/v3/ledger/repays` to compute net leverage over time.\n\nResults are sorted by `snapshotDate` (descending — newest first). Ordering is not configurable from the query string.\n\nSupports three response formats via the `format` query parameter:\n- **json** (default) — paginated JSON (default limit 100, max 1000).\n- **csv** — streamed CSV file download (up to 1,000,000 rows). Columns: snapshotDate, amountUsd, organizationId, organizationName, createdAt.\n- **event-stream** — Server-Sent Events stream (up to 1,000,000 rows). Each entry is emitted as a named `entry` event with JSON data. A final `done` event carries `{\"total\": N}`. Connect with `EventSource` or `fetch`:\n\n```js\nconst es = new EventSource('/v3/ledger/cumulative-collateral?organizationId={id}&format=event-stream', {\n  headers: { 'x-api-key': 'cc_...' },\n});\nes.addEventListener('entry', (e) => console.log(JSON.parse(e.data)));\nes.addEventListener('done', (e) => { console.log('total:', JSON.parse(e.data).total); es.close(); });\n```\n\nRequires org membership or vault curator role (public orgs only).","parameters":[{"schema":{"type":"string","format":"uuid","maxLength":36},"in":"query","name":"organizationId","required":true,"description":"Organization ID (must be an org the caller is a member of, or a public org if caller is a vault curator)."},{"schema":{"type":"string","format":"date"},"in":"query","name":"startDate","required":false,"description":"Optional filter. Inclusive start date (YYYY-MM-DD); restricts results to `occurredAt >= startDate` (or `snapshotDate` for collateral-snapshots). Omit to leave the start unbounded."},{"schema":{"type":"string","format":"date"},"in":"query","name":"endDate","required":false,"description":"Optional filter. Inclusive end date (YYYY-MM-DD). Omit to leave the end unbounded."},{"schema":{"type":"integer","minimum":1},"in":"query","name":"limit","required":false,"description":"Maximum records returned. Format-dependent: `format=json` capped at 1000 (default 100); `format=csv|event-stream` capped at 1,000,000 (default 1,000,000). Values outside these caps are silently clamped server-side."},{"schema":{"type":"integer","minimum":0,"default":0},"in":"query","name":"offset","required":false,"description":"Number of records to skip from the start (JSON pagination only — ignored for csv/event-stream)."},{"schema":{"type":"string","enum":["json","csv","event-stream"],"default":"json"},"in":"query","name":"format","required":false,"description":"Response format. `json` returns paginated JSON. `csv` streams a CSV file download. `event-stream` returns Server-Sent Events: each row is a named `entry` event; a final `done` event carries `{\"total\": N}`."}],"responses":{"200":{"description":"Point-in-time collateral USD snapshots (one row per org per day).","content":{"application/json":{"schema":{"type":"object","required":["entries","pagination"],"properties":{"entries":{"type":"array","items":{"type":"object","required":["id","organizationId","webCaptureId","amountUsd","snapshotDate","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"organizationId":{"type":"string","format":"uuid"},"organizationName":{"type":"string","nullable":true},"webCaptureId":{"type":"string","format":"uuid"},"amountUsd":{"type":"string","description":"USD value (6 fractional digits). Returned as a string to avoid floating-point precision loss."},"snapshotDate":{"type":"string","format":"date"},"createdAt":{"type":"string","format":"date-time"}}}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}},"text/csv":{"schema":{"type":"string","description":"CSV file download. Columns: snapshotDate, amountUsd, organizationId, organizationName, createdAt."}},"text/event-stream":{"schema":{"type":"string","description":"SSE stream. Named `entry` events carry one row each; a final `done` event carries `{\"total\": N}`."}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
````


# Benchmarks

Benchmark vault APY rates computed from on-chain snapshots

## Get historical vault APY

> Returns a daily timeseries of rolling 7-day APY for any vault with on-chain snapshots. Works with both internal vaults (sharePrice) and ERC-4626 vaults (convertToAssets). Specify the vault by address or token symbol.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Benchmarks","description":"Benchmark vault APY rates computed from on-chain snapshots"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]},{}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/benchmarks/vault-apy":{"get":{"operationId":"getBenchmarkVaultApy","summary":"Get historical vault APY","tags":["Benchmarks"],"description":"Returns a daily timeseries of rolling 7-day APY for any vault with on-chain snapshots. Works with both internal vaults (sharePrice) and ERC-4626 vaults (convertToAssets). Specify the vault by address or token symbol.","parameters":[{"schema":{"type":"string"},"in":"query","name":"address","required":false,"description":"Vault contract address (e.g., 0xabc...)"},{"schema":{"type":"string"},"in":"query","name":"symbol","required":false,"description":"Token symbol to look up the vault (e.g., stataEthUSDC)"},{"schema":{"type":"string"},"in":"query","name":"networkId","required":true,"description":"CAIP-2 network identifier (e.g., eip155:1 for Ethereum, eip155:8453 for Base)"},{"schema":{"type":"string","format":"date"},"in":"query","name":"from","required":false,"description":"Start date (YYYY-MM-DD). Defaults to earliest available data."},{"schema":{"type":"string","format":"date"},"in":"query","name":"to","required":false,"description":"End date (YYYY-MM-DD). Defaults to latest available data."}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["address","networkId","data"],"properties":{"address":{"type":"string"},"networkId":{"type":"string"},"symbol":{"type":"string"},"data":{"type":"array","items":{"type":"object","required":["date","apyPct7D"],"properties":{"date":{"type":"string","format":"date"},"apyPct7D":{"type":["null","number"],"description":"Rolling 7-day APY in percent (e.g., 5.25 = 5.25%)"}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Get historical benchmark rate

> Returns a daily timeseries of a benchmark rate from the prices table. Supported symbols: FED\_FUNDS\_RATE (Federal Funds Effective Rate) and SOFR\_30D\_AVG (30-Day Average SOFR).

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Benchmarks","description":"Benchmark vault APY rates computed from on-chain snapshots"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]},{}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/benchmarks/rate":{"get":{"operationId":"getBenchmarkRate","summary":"Get historical benchmark rate","tags":["Benchmarks"],"description":"Returns a daily timeseries of a benchmark rate from the prices table. Supported symbols: FED_FUNDS_RATE (Federal Funds Effective Rate) and SOFR_30D_AVG (30-Day Average SOFR).","parameters":[{"schema":{"type":"string","default":"FED_FUNDS_RATE"},"in":"query","name":"symbol","required":false,"description":"Rate symbol: FED_FUNDS_RATE or SOFR_30D_AVG. Defaults to FED_FUNDS_RATE."},{"schema":{"type":"string","format":"date"},"in":"query","name":"from","required":false,"description":"Start date (YYYY-MM-DD). Defaults to earliest available."},{"schema":{"type":"string","format":"date"},"in":"query","name":"to","required":false,"description":"End date (YYYY-MM-DD). Defaults to latest available."}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["symbol","data"],"properties":{"symbol":{"type":"string"},"data":{"type":"array","items":{"type":"object","required":["date","rate"],"properties":{"date":{"type":"string","format":"date"},"rate":{"type":"number","description":"Rate value (e.g., 4.33 = 4.33%)"}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```


# Self Report

Self-reported invoice and cashflow data endpoints

## Submit self-reported cashflows

> Submit cashflow items for the authenticated organization. Each entry in \`items\` takes one of three shapes, selected by its \`type\` field:\
> \
> \- \`transaction\` — an individual transaction with a precise \`datetime\` and a required \`externalId\` for deduplication.\
> \- \`aggregate\` — a daily total for a \`date\` (zero allowed for no-activity days).\
> \- \`collateral\` — a cumulative collateral snapshot for a \`date\`.\
> \
> Items flow through the standard capture → normalize pipeline. Transactions and aggregates become ledger entries; collateral snapshots are stored in the dedicated collateral\_snapshots table.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Self Report","description":"Self-reported invoice and cashflow data endpoints"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/self-report/cashflows":{"post":{"operationId":"submitSelfReportCashflows","summary":"Submit self-reported cashflows","tags":["Self Report"],"description":"Submit cashflow items for the authenticated organization. Each entry in `items` takes one of three shapes, selected by its `type` field:\n\n- `transaction` — an individual transaction with a precise `datetime` and a required `externalId` for deduplication.\n- `aggregate` — a daily total for a `date` (zero allowed for no-activity days).\n- `collateral` — a cumulative collateral snapshot for a `date`.\n\nItems flow through the standard capture → normalize pipeline. Transactions and aggregates become ledger entries; collateral snapshots are stored in the dedicated collateral_snapshots table.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","minItems":1,"items":{"description":"A single cashflow item. Its shape is selected by the `type` field: transaction, aggregate, or collateral.","oneOf":[{"title":"Transaction","description":"Individual transaction (type=transaction). Requires a precise datetime and an externalId for deduplication.","type":"object","required":["type","amount","currency","datetime","direction","externalId"],"properties":{"type":{"type":"string","enum":["transaction"]},"amount":{"type":"number","exclusiveMinimum":0,"description":"Transaction amount (positive)"},"currency":{"type":"string","minLength":1,"maxLength":20,"description":"Currency code (stored as-is)"},"datetime":{"type":"string","format":"date-time","description":"ISO 8601 datetime (e.g. 2026-03-01T14:30:00Z)"},"direction":{"type":"string","enum":["inflow","outflow"],"description":"Cashflow direction"},"externalId":{"type":"string","minLength":1,"maxLength":255,"description":"Customer transaction ID (required for deduplication)"},"category":{"type":"string","maxLength":100}}},{"title":"Aggregate","description":"Daily aggregate total (type=aggregate). Zero allowed for no-activity days.","type":"object","required":["type","amount","currency","date","direction"],"properties":{"type":{"type":"string","enum":["aggregate"]},"amount":{"type":"number","minimum":0,"description":"Aggregate amount (zero allowed for no-activity days)"},"currency":{"type":"string","minLength":1,"maxLength":20,"description":"Currency code (stored as-is)"},"date":{"type":"string","format":"date","description":"ISO 8601 date (YYYY-MM-DD)"},"direction":{"type":"string","enum":["inflow","outflow"],"description":"Cashflow direction"},"category":{"type":"string","maxLength":100}}},{"title":"Collateral","description":"Cumulative collateral snapshot (type=collateral).","type":"object","required":["type","amount","currency","date"],"properties":{"type":{"type":"string","enum":["collateral"]},"amount":{"type":"number","minimum":0,"description":"Cumulative collateral amount (zero allowed)"},"currency":{"type":"string","minLength":1,"maxLength":20,"description":"Currency code (stored as-is)"},"date":{"type":"string","format":"date","description":"Snapshot date (YYYY-MM-DD)"},"category":{"type":"string","maxLength":100}}}]}}},"additionalProperties":false}}}},"responses":{"202":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["message","captureId","jobId","itemCount"],"properties":{"message":{"type":"string"},"captureId":{"type":"string","format":"uuid"},"jobId":{"type":"string"},"itemCount":{"type":"integer"}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```


# Users

User profile and settings management

## Check user verification status

> Check if the authenticated user is verified (via KYC, legacy onboarding, KYB organization membership, or legacy KYB)

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Users","description":"User profile and settings management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/users/me/verified":{"get":{"operationId":"checkUserVerification","summary":"Check user verification status","tags":["Users"],"description":"Check if the authenticated user is verified (via KYC, legacy onboarding, KYB organization membership, or legacy KYB)","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["verified"],"properties":{"verified":{"type":"boolean","description":"Whether the user is verified through KYC, legacy onboarding, or membership in a KYB-verified or legacy KYB organization"}}}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Record biometric consent

> Record biometric consent for the authenticated user

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Users","description":"User profile and settings management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/users/me/consent":{"post":{"operationId":"recordBiometricConsent","summary":"Record biometric consent","tags":["Users"],"description":"Record biometric consent for the authenticated user","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["biometricConsentGiven","biometricConsentVersion"],"properties":{"biometricConsentGiven":{"type":"boolean","description":"Whether the user has given biometric consent"},"biometricConsentVersion":{"type":"string","description":"Version of the biometric consent accepted"}}}}}},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","message","user"],"properties":{"success":{"type":"boolean"},"message":{"type":"string"},"user":{"type":"object","required":["id","email","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string"},"firstName":{"type":"string","nullable":true},"lastName":{"type":"string","nullable":true},"metadata":{"type":"object","nullable":true,"additionalProperties":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## List user's organizations

> List all organizations the authenticated user is a member of. Returns organizations, per-org functional access roles ("borrower", "vault-curator"), and a top-level union of all functional roles. Not all members receive functional roles; members without any will have an empty roles array for that org.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Users","description":"User profile and settings management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"Organization":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string","format":"uuid","description":"Organization unique identifier"},"name":{"type":"string","maxLength":255,"description":"Organization display name"},"slug":{"type":"string","maxLength":100,"description":"URL-friendly identifier"},"header":{"type":"string","nullable":true,"description":"Short tagline or headline for the organization profile"},"description":{"type":"string","nullable":true,"description":"Brief summary of the organization"},"overview":{"type":"string","nullable":true,"description":"Long-form organization description (may contain Markdown)"},"links":{"type":"array","description":"Organization links and image assets. Labels starting with \"#\" are image assets (e.g. \"#logo\", \"#header\"); all others are external links (e.g. \"Twitter\", \"Website\").","items":{"type":"object","required":["id","label","url"],"properties":{"id":{"type":"string","format":"uuid","description":"Link unique identifier"},"label":{"type":"string","description":"Link type. \"#logo\" and \"#header\" denote image assets; other values (e.g. \"Twitter\", \"Website\") denote external links."},"linkText":{"type":"string","nullable":true,"description":"Display text for external links (e.g. \"@raincards\", \"rain.xyz\")"},"iconUrl":{"type":"string","nullable":true,"description":"Icon image URL for external links"},"url":{"type":"string","description":"Target URL (image URL for asset links, destination URL for external links)"}}}}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/users/me/organizations":{"get":{"operationId":"listMyOrganizations","summary":"List user's organizations","tags":["Users"],"description":"List all organizations the authenticated user is a member of. Returns organizations, per-org functional access roles (\"borrower\", \"vault-curator\"), and a top-level union of all functional roles. Not all members receive functional roles; members without any will have an empty roles array for that org.","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["organizations","organizationAccessById","roles"],"properties":{"organizations":{"type":"array","items":{"$ref":"#/components/schemas/Organization"}},"organizationAccessById":{"type":"object","additionalProperties":{"type":"object","required":["roles"],"properties":{"roles":{"type":"array","items":{"type":"string","enum":["borrower","vault-curator","vault-depositor-manager"]},"description":"Functional access roles for this organization. \"borrower\": member of a borrower org. \"vault-curator\": member of a vault curator org. \"vault-depositor-manager\": admin of a vault curator org. Not all members receive functional roles."}}},"description":"Map of organizationId to functional access roles."},"roles":{"type":"array","items":{"type":"string","enum":["borrower","vault-curator","vault-depositor-manager"]},"description":"Union of all functional roles the user has across all organizations."}}}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## List KYB-eligible organizations

> List organizations where the authenticated user is an admin with KYB eligibility status. Returns simplified organization data: name, slug, and kybEligible flag.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Users","description":"User profile and settings management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/users/me/organizations/kyb-eligible":{"get":{"operationId":"listKybEligibleOrganizations","summary":"List KYB-eligible organizations","tags":["Users"],"description":"List organizations where the authenticated user is an admin with KYB eligibility status. Returns simplified organization data: name, slug, and kybEligible flag.","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["organizations"],"properties":{"organizations":{"type":"array","items":{"type":"object","required":["name","slug","kybEligible"],"properties":{"name":{"type":"string","maxLength":255},"slug":{"type":"string","maxLength":100},"kybEligible":{"type":"boolean","description":"Whether the organization is eligible for KYB verification (true if user is admin and org is NOT yet verified)"}}}}}}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```


# Wallet Attestation

Wallet ownership verification via message signing

## Generate wallet attestation challenge

> Generate a challenge message for the given wallet address. The user must sign this message to prove ownership.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Wallet Attestation","description":"Wallet ownership verification via message signing"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/users/me/wallets/challenge":{"post":{"operationId":"generateWalletChallenge","summary":"Generate wallet attestation challenge","tags":["Wallet Attestation"],"description":"Generate a challenge message for the given wallet address. The user must sign this message to prove ownership.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["address","namespace"],"properties":{"address":{"type":"string","maxLength":42,"pattern":"^0x[0-9a-fA-F]{40}$","description":"EVM wallet address to attest."},"namespace":{"type":"string","enum":["eip155"],"description":"Address namespace. Currently only \"eip155\" (EVM) is supported."}}}}}},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["message","nonce","expiresIn"],"properties":{"message":{"type":"string","description":"Challenge message to sign"},"nonce":{"type":"string","description":"Challenge nonce"},"expiresIn":{"type":"integer","description":"Nonce TTL in seconds"}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Verify wallet attestation

> Submit the signed attestation message to prove wallet ownership and link the address to your account.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Wallet Attestation","description":"Wallet ownership verification via message signing"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/users/me/wallets/attest":{"post":{"operationId":"verifyWalletAttestation","summary":"Verify wallet attestation","tags":["Wallet Attestation"],"description":"Submit the signed attestation message to prove wallet ownership and link the address to your account.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["address","namespace","signature","message"],"properties":{"address":{"type":"string","maxLength":42,"pattern":"^0x[0-9a-fA-F]{40}$","description":"EVM wallet address being attested."},"namespace":{"type":"string","enum":["eip155"],"description":"Network namespace the user is attesting under. The signature is NOT chain-bound — for EVM ('eip155'), the same attestation covers all eip155 chains."},"signature":{"type":"string","description":"The signed message signature from the wallet."},"message":{"type":"string","description":"The attestation message that was signed (returned from the challenge endpoint)."}}}}}},"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["id","address","networkNamespace","verifiedAt","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"address":{"type":"string"},"networkNamespace":{"type":"string"},"verifiedAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"subscriptions":{"type":"array","items":{"type":"object","required":["type","enabled"],"properties":{"type":{"type":"string","enum":["wallet_transactional","weekly_portfolio"]},"enabled":{"type":"boolean"}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## List the user's wallets (optionally including org multisigs)

> List the user's attested EOAs. Pass \`?include=multisigs\` to also include org-owned multisigs the user has access to.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Wallet Attestation","description":"Wallet ownership verification via message signing"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/users/me/wallets":{"get":{"operationId":"listAttestedWallets","summary":"List the user's wallets (optionally including org multisigs)","tags":["Wallet Attestation"],"description":"List the user's attested EOAs. Pass `?include=multisigs` to also include org-owned multisigs the user has access to.","parameters":[{"schema":{"type":"string","enum":["multisigs"]},"in":"query","name":"include","required":false,"description":"Optional extras to include in the response. Currently only `multisigs` is supported."}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["wallets"],"properties":{"wallets":{"type":"array","items":{"type":"object","required":["type","address","subscriptions"],"properties":{"type":{"type":"string","enum":["eoa","multisig","org_eoa"]},"id":{"type":"string"},"address":{"type":"string"},"networkNamespace":{"type":"string"},"verifiedAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"networkId":{"type":"string"},"organizationId":{"type":"string","format":"uuid"},"organizationName":{"type":"string"},"subscriptions":{"type":"array","items":{"type":"object","required":["type","enabled"],"properties":{"type":{"type":"string","enum":["wallet_transactional","weekly_portfolio"]},"enabled":{"type":"boolean"}}}}}}}}}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Update email subscription preferences for the authenticated user

> Subscribe or unsubscribe in bulk. Each change is identified by (address, networkId, type); \`enabled: true\` inserts a row, \`enabled: false\` deletes one. All cells are user-editable; defaults at wallet-create / org-join time are managed server-side.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Wallet Attestation","description":"Wallet ownership verification via message signing"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/users/me/email-subscriptions":{"put":{"operationId":"updateEmailSubscriptions","summary":"Update email subscription preferences for the authenticated user","tags":["Wallet Attestation"],"description":"Subscribe or unsubscribe in bulk. Each change is identified by (address, networkId, type); `enabled: true` inserts a row, `enabled: false` deletes one. All cells are user-editable; defaults at wallet-create / org-join time are managed server-side.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["changes"],"properties":{"changes":{"type":"array","items":{"type":"object","required":["address","networkId","type","enabled"],"properties":{"address":{"type":"string","maxLength":42,"pattern":"^0x[0-9a-fA-F]{40}$","description":"EVM address. The server normalizes to EIP-55 checksum form before lookup, so lowercase or mixed case are accepted."},"networkId":{"type":"string","maxLength":50},"type":{"type":"string","enum":["wallet_transactional","weekly_portfolio"]},"enabled":{"type":"boolean"}}}}}}}}},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["wallets"],"properties":{"wallets":{"type":"array","items":{"type":"object","required":["type","address","subscriptions"],"properties":{"type":{"type":"string","enum":["eoa","multisig","org_eoa"]},"id":{"type":"string"},"address":{"type":"string"},"networkNamespace":{"type":"string"},"verifiedAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"networkId":{"type":"string"},"organizationId":{"type":"string","format":"uuid"},"organizationName":{"type":"string"},"subscriptions":{"type":"array","items":{"type":"object","required":["type","enabled"],"properties":{"type":{"type":"string","enum":["wallet_transactional","weekly_portfolio"]},"enabled":{"type":"boolean"}}}}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```


# API Keys

API key management

## List API keys

> List all API keys scoped to the specified organization.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"API Keys","description":"API key management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/api-keys":{"get":{"operationId":"listApiKeys","summary":"List API keys","tags":["API Keys"],"description":"List all API keys scoped to the specified organization.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"organizationId","required":true,"description":"Organization ID — only keys belonging to this organization are returned. Example: 550e8400-e29b-41d4-a716-446655440000"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"object","required":["id","organizationId","keyPrefix","name","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"organizationId":{"type":"string","format":"uuid"},"keyPrefix":{"type":"string"},"name":{"type":"string"},"lastUsedAt":{"type":"string","format":"date-time","nullable":true},"expiresAt":{"type":"string","format":"date-time","nullable":true},"revokedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Create API key

> Create a new API key for the specified organization. The key authenticates requests as a member of that organization.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"API Keys","description":"API key management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/api-keys":{"post":{"operationId":"createApiKey","summary":"Create API key","tags":["API Keys"],"description":"Create a new API key for the specified organization. The key authenticates requests as a member of that organization.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"organizationId":{"type":"string","format":"uuid","description":"The organization this API key belongs to. Requests authenticated with this key will be made as a member of this organization. Example: 550e8400-e29b-41d4-a716-446655440000"},"name":{"type":"string","maxLength":255,"description":"Name for the API key"},"expiresInDays":{"type":"number","description":"Number of days until the key expires"}},"required":["organizationId","name"]}}}},"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["id","organizationId","keyPrefix","name","fullKey","createdAt","message"],"properties":{"id":{"type":"string","format":"uuid"},"organizationId":{"type":"string","format":"uuid"},"keyPrefix":{"type":"string"},"name":{"type":"string"},"fullKey":{"type":"string","description":"Full API key. Only returned once at creation — save it immediately."},"expiresAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"message":{"type":"string"}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Revoke an API key

> Revoke an API key. The organization is derived from the key itself.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"API Keys","description":"API key management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/api-keys/{apiKeyId}":{"delete":{"operationId":"revokeApiKey","summary":"Revoke an API key","tags":["API Keys"],"description":"Revoke an API key. The organization is derived from the key itself.","parameters":[{"schema":{"type":"string"},"in":"path","name":"apiKeyId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```


# Organizations

Organization management

## List org multisig wallets

> List Safe multisig wallets registered to an organization, with on-chain owner resolution and attestation status.

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Organizations","description":"Organization management"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key in the format: cc_xxx_yyy (for customer API routes)"},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk authentication token (session JWT or Clerk OAuth access token) used by Credit Coop"},"OAuth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.creditcoop.xyz/oauth/authorize","tokenUrl":"https://clerk.creditcoop.xyz/oauth/token","scopes":{"openid":"OpenID Connect","email":"User email","profile":"User profile"}}},"description":"Credit Coop OAuth"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}},"paths":{"/v3/organizations/{orgId}/multisigs":{"get":{"operationId":"listOrgMultisigs","summary":"List org multisig wallets","tags":["Organizations"],"description":"List Safe multisig wallets registered to an organization, with on-chain owner resolution and attestation status.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"orgId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["multisigs"],"properties":{"multisigs":{"type":"array","items":{"type":"object","required":["id","address","networkId","owners","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"address":{"type":"string"},"networkId":{"type":"string"},"name":{"type":"string","nullable":true},"owners":{"type":"array","items":{"type":"object","required":["address"],"properties":{"address":{"type":"string"},"attestation":{"nullable":true,"type":"object","required":["verifiedAt","userId"],"properties":{"verifiedAt":{"type":"string","format":"date-time"},"userId":{"type":"string"},"userEmail":{"type":"string","nullable":true},"userName":{"type":"string","nullable":true}}}}}},"createdAt":{"type":"string","format":"date-time"}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```


# Health

Health check endpoints

## Check API health

> Check API health and status

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"tags":[{"name":"Health","description":"Health check endpoints"}],"servers":[{"url":"https://api.creditcoop.xyz"}],"paths":{"/health":{"get":{"operationId":"getHealth","summary":"Check API health","tags":["Health"],"description":"Check API health and status","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"uptime":{"type":"number","description":"Server uptime in seconds"},"version":{"type":"string"}}}}}}}}}}}
```


# Models

## The ErrorResponse object

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"components":{"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}}}}
```

## The Organization object

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"components":{"schemas":{"Organization":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string","format":"uuid","description":"Organization unique identifier"},"name":{"type":"string","maxLength":255,"description":"Organization display name"},"slug":{"type":"string","maxLength":100,"description":"URL-friendly identifier"},"header":{"type":"string","nullable":true,"description":"Short tagline or headline for the organization profile"},"description":{"type":"string","nullable":true,"description":"Brief summary of the organization"},"overview":{"type":"string","nullable":true,"description":"Long-form organization description (may contain Markdown)"},"links":{"type":"array","description":"Organization links and image assets. Labels starting with \"#\" are image assets (e.g. \"#logo\", \"#header\"); all others are external links (e.g. \"Twitter\", \"Website\").","items":{"type":"object","required":["id","label","url"],"properties":{"id":{"type":"string","format":"uuid","description":"Link unique identifier"},"label":{"type":"string","description":"Link type. \"#logo\" and \"#header\" denote image assets; other values (e.g. \"Twitter\", \"Website\") denote external links."},"linkText":{"type":"string","nullable":true,"description":"Display text for external links (e.g. \"@raincards\", \"rain.xyz\")"},"iconUrl":{"type":"string","nullable":true,"description":"Icon image URL for external links"},"url":{"type":"string","description":"Target URL (image URL for asset links, destination URL for external links)"}}}}}}}}}
```

## The Pagination object

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"components":{"schemas":{"Pagination":{"type":"object","required":["total","limit","offset"],"properties":{"total":{"type":"integer","description":"Total number of records matching the query"},"limit":{"type":"integer","description":"Maximum number of records returned per page"},"offset":{"type":"integer","description":"Number of records skipped from the start"}}}}}}
```

## The IdParam object

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"components":{"schemas":{"IdParam":{"type":"object","required":["id"],"properties":{"id":{"type":"string","format":"uuid","description":"Resource ID"}}}}}}
```

## The OrganizationIdParam object

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"components":{"schemas":{"OrganizationIdParam":{"type":"object","required":["organizationId"],"properties":{"organizationId":{"type":"string","format":"uuid","description":"Organization ID"}}}}}}
```

## The Token object

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"components":{"schemas":{"Token":{"type":"object","required":["id","address","networkId","symbol","decimals"],"properties":{"id":{"type":"string","format":"uuid","description":"Token unique identifier"},"address":{"type":"string","description":"Token contract address"},"networkId":{"type":"string","description":"CAIP-2 network identifier"},"symbol":{"type":"string","description":"Token ticker symbol (e.g. \"USDC\", \"WETH\")"},"name":{"type":"string","nullable":true,"description":"Full token name"},"decimals":{"type":"integer","minimum":0,"maximum":255,"description":"Number of decimal places for the token"},"wraps":{"type":"string","nullable":true,"description":"Underlying asset this token represents (e.g. \"USD\" for USDC, \"ETH\" for WETH)"},"iconUrl":{"type":"string","nullable":true,"description":"URL of the token icon image"},"coingeckoId":{"type":"string","nullable":true,"description":"CoinGecko API identifier for price lookups"}}}}}}
```

## The Network object

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"components":{"schemas":{"Network":{"type":"object","required":["networkId","displayName"],"properties":{"networkId":{"type":"string","description":"CAIP-2 network identifier"},"displayName":{"type":"string","description":"Human-readable network name (e.g. \"Ethereum Mainnet\")"},"explorerUrl":{"type":"string","nullable":true,"description":"Block explorer base URL"},"rpcUrl":{"type":"string","nullable":true,"description":"RPC endpoint URL"},"iconUrl":{"type":"string","nullable":true,"description":"URL of the network icon image"},"nativeCurrencySymbol":{"type":"string","nullable":true,"description":"Native currency ticker (e.g. \"ETH\")"},"nativeCurrencyDecimals":{"type":"integer","nullable":true,"description":"Native currency decimal places"}}}}}}
```

## The Vault object

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"components":{"schemas":{"Vault":{"type":"object","required":["id","address","networkId","protocolVersion","label","organizationId","deployedAt"],"properties":{"id":{"type":"string","format":"uuid","description":"Vault unique identifier"},"address":{"type":"string","description":"Vault contract address"},"networkId":{"type":"string","description":"CAIP-2 network identifier"},"protocolVersion":{"type":"string","nullable":true,"description":"Credit Coop protocol/contract generation (\"v1\", \"v2\", or \"v3\"). Determines which fields apply — several facility and credit-line fields are v3 only. Null when not classified."},"label":{"type":"string","nullable":true,"description":"Display label for the vault. Always present; null if not configured."},"organizationId":{"type":"string","format":"uuid","nullable":true,"description":"Vault curator organization ID"},"deployedAt":{"type":"string","format":"date-time","nullable":true,"description":"Timestamp when the vault contract was deployed"},"organization":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Organization"}],"description":"Organization details with links. Only included when expand includes \"organization\"."},"relatedAddresses":{"type":"object","nullable":true,"description":"On-chain related addresses. Only included when expand includes \"related-addresses\".","properties":{"creditStrategy":{"type":"string","nullable":true,"description":"CreditStrategy contract address. Manages credit allocation from vault funds to credit facilities."},"liquidStrategy":{"type":"string","nullable":true,"description":"LiquidStrategy contract address. Manages liquid asset reserves in the vault."},"vaultCurator":{"type":"string","nullable":true,"description":"Vault curator (manager) address of the CreditStrategy contract. Retrieved by calling manager() on the creditStrategy."},"whitelister":{"type":"string","nullable":true,"description":"Access-control authority that gates the vault deposit whitelist. Set per vault. Null for v2 vaults."}}},"assets":{"type":"object","nullable":true,"description":"Asset information. Only included when expand includes \"assets\".","properties":{"assetToken":{"type":"string","nullable":true,"description":"Asset token address"},"shareToken":{"type":"string","nullable":true,"description":"Share token address"},"decimals":{"type":"integer","nullable":true,"description":"Asset token decimals"},"totalAssets":{"type":"string","nullable":true,"description":"Total assets in the vault (raw uint256 — divide by 10^decimals to get human-readable value)"},"totalLiquidAssets":{"type":"string","nullable":true,"description":"Total liquid assets. Vault's balance - total pending deposits - claimable redeem assets + liquid strategy total assets + uninvested credit strategy assets (raw uint256 — divide by 10^decimals to get human-readable value)"},"totalSupply":{"type":"string","nullable":true,"description":"Total supply of vault shares (raw uint256 — divide by 10^decimals to get human-readable value)"},"sharePrice":{"type":"string","nullable":true,"description":"Share price of the vault (raw uint256 — divide by 10^decimals to get human-readable value)"},"baseUnit":{"type":"string","nullable":true,"description":"Minimum accounting unit used by the CreditStrategy for scaling interest calculations (raw uint256). Equal to 10^decimals."},"totalActiveCredit":{"type":"string","nullable":true,"description":"Total active credit from CreditStrategy. Deposits plus accrued and repaid interest for all credit lines (raw uint256 — divide by 10^decimals to get human-readable value)"},"uninvestedCreditAssets":{"type":"string","nullable":true,"description":"Uninvested credit assets. Asset token balance held by CreditStrategy (raw uint256 — divide by 10^decimals to get human-readable value)"}}},"apy":{"type":"object","nullable":true,"description":"APY data from historical sharePrice snapshots. Only included when expand includes \"apy\".","properties":{"apyPct30D":{"type":"number","nullable":true,"description":"30-day APY in percent (e.g. 5.0 = 5%). Null if insufficient snapshot data."}}},"fees":{"type":"object","nullable":true,"description":"Credit strategy fees in basis points. Only included when expand includes \"fees\".","properties":{"managementFee":{"type":"integer","description":"Management fee in basis points (e.g. 200 = 2%)"},"performanceFee":{"type":"integer","description":"Performance fee in basis points (e.g. 1000 = 10%)"}}}}},"Organization":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string","format":"uuid","description":"Organization unique identifier"},"name":{"type":"string","maxLength":255,"description":"Organization display name"},"slug":{"type":"string","maxLength":100,"description":"URL-friendly identifier"},"header":{"type":"string","nullable":true,"description":"Short tagline or headline for the organization profile"},"description":{"type":"string","nullable":true,"description":"Brief summary of the organization"},"overview":{"type":"string","nullable":true,"description":"Long-form organization description (may contain Markdown)"},"links":{"type":"array","description":"Organization links and image assets. Labels starting with \"#\" are image assets (e.g. \"#logo\", \"#header\"); all others are external links (e.g. \"Twitter\", \"Website\").","items":{"type":"object","required":["id","label","url"],"properties":{"id":{"type":"string","format":"uuid","description":"Link unique identifier"},"label":{"type":"string","description":"Link type. \"#logo\" and \"#header\" denote image assets; other values (e.g. \"Twitter\", \"Website\") denote external links."},"linkText":{"type":"string","nullable":true,"description":"Display text for external links (e.g. \"@raincards\", \"rain.xyz\")"},"iconUrl":{"type":"string","nullable":true,"description":"Icon image URL for external links"},"url":{"type":"string","description":"Target URL (image URL for asset links, destination URL for external links)"}}}}}}}}}
```

## The CreditFacility object

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"components":{"schemas":{"CreditFacility":{"type":"object","required":["id","address","networkId","protocolVersion","label","organizationId"],"properties":{"id":{"type":"string","format":"uuid","description":"Credit facility unique identifier"},"address":{"type":"string","description":"SecuredLine contract address"},"networkId":{"type":"string","description":"CAIP-2 network identifier"},"protocolVersion":{"type":"string","nullable":true,"description":"Credit Coop protocol/contract generation (\"v1\", \"v2\", or \"v3\"). Determines which fields apply — several facility and credit-line fields are v3 only. Null when not classified."},"label":{"type":"string","nullable":true,"description":"Display label for the credit facility. Always present; null if not configured."},"organizationId":{"type":"string","format":"uuid","nullable":true,"description":"Borrower organization ID"},"organization":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Organization"}],"description":"Organization details with links. Only included when expand includes \"organization\"."},"relatedAddresses":{"type":"object","nullable":true,"description":"On-chain related addresses. Only included when expand includes \"related-addresses\".","properties":{"spigot":{"type":"string","nullable":true,"description":"v1/v2 only. Spigot contract address. Captures and routes borrower revenue to debt repayment. Null for v3 facilities (no spigot layer)."},"borrower":{"type":"string","nullable":true,"description":"Address authorized to borrow, repay, and close credit lines. Present on all versions."},"admin":{"type":"string","nullable":true,"description":"v1/v2 only. Credit facility administrator address. Null for v3 facilities."},"spigotOperator":{"type":"string","nullable":true,"description":"v1/v2 only. Address authorized to execute revenue claims on the Spigot. Null for v3 facilities."},"escrow":{"type":"string","nullable":true,"description":"v2 only. Escrow contract address. Holds collateral posted by the borrower and enforces the minimum collateral ratio. Null for v1/v3 facilities (v3 collateral lives on the Servicing contract)."},"servicing":{"type":"string","nullable":true,"description":"v3 only. The facility's bound Servicing contract — the per-borrower hub for covenants, collateral, and cross-default. Null for v1/v2 facilities."},"servicingId":{"type":"string","format":"uuid","nullable":true,"description":"v3 only. Resource ID of the bound Servicing (use with GET /v3/servicings/:id). Null when the Servicing address is not registered, or for v1/v2 facilities."},"commitmentToken":{"type":"string","nullable":true,"description":"v3 only. The ERC-721 CommitmentToken singleton — the NFT contract representing every commitment/credit line in the facility (ownerOf(lineTokenId) is the lender). Facility-wide: the same contract for every line. Null for v1/v2 facilities (no commitment-NFT layer)."}}},"fees":{"type":"object","nullable":true,"description":"Fee configuration for the Credit Facility. Only included when expand includes \"fees\".","required":["originationFee","swapFee","servicingFee","drawFee","repayFee"],"properties":{"originationFee":{"type":"string","nullable":true,"description":"Origination fee (basis points). Present on v2 and v3."},"swapFee":{"type":"string","nullable":true,"description":"v2 only. Swap fee (basis points). Null for v3."},"servicingFee":{"type":"string","nullable":true,"description":"v2 only. Servicing fee (basis points). Null for v3."},"drawFee":{"type":"string","nullable":true,"description":"v3 only. Per-draw fee (basis points, FEE_DRAW). Null for v1/v2."},"repayFee":{"type":"string","nullable":true,"description":"v3 only. Per-repay fee (basis points, FEE_REPAY). Null for v1/v2."}}},"counts":{"type":"object","nullable":true,"description":"Active credit lines and open proposals counts. Only included when expand includes \"counts\".","required":["activeCreditLines","openProposals"],"properties":{"activeCreditLines":{"type":"integer","description":"Number of active credit lines"},"openProposals":{"type":"integer","description":"Number of open mutual consent proposals"}}},"status":{"type":"object","nullable":true,"description":"On-chain status for this facility. Only included when expand includes \"status\". An open facility may report LIQUIDATABLE when its borrower is in cross-default; once a facility is closed it reports REPAID and reflects only its own terminal outcome, never absorbing the borrower's wider default state. Borrower-wide default and covenant breach levels are reported per cross-default group on GET /v3/borrowers (expand=status).","required":["code","label","facilityClosed"],"properties":{"code":{"type":"integer","description":"Numeric status code (0: UNINITIALIZED, 1: ACTIVE, 2: LIQUIDATABLE, 3: REPAID, 4: INSOLVENT, 5: ABORTED)"},"label":{"type":"string","enum":["UNINITIALIZED","ACTIVE","LIQUIDATABLE","REPAID","INSOLVENT","ABORTED","UNKNOWN"],"description":"Human-readable status label. UNKNOWN is returned when the on-chain status code is outside the known range (e.g., a new status added by a future contract version)."},"facilityClosed":{"type":"boolean","description":"Whether this specific facility is closed (terminal). Always present whenever status is present (the entire status object is omitted when unavailable). For a closed facility code/label report REPAID; for an open facility they may additionally reflect borrower-wide cross-default (LIQUIDATABLE)."}}},"collateral":{"type":"object","nullable":true,"description":"On-chain collateral state from the Escrow contract. Only included when expand includes \"collateral\". Null when the facility has no escrow, RPC is unavailable, or the facility predates the Escrow architecture.","required":["maxLtvBps","totalOutstandingDebt","collateralValue","ltvBps","targetLtvBps","collateralTokens"],"properties":{"maxLtvBps":{"type":"string","nullable":true,"description":"Maximum loan-to-value ratio allowed for this facility, in basis points (10000 = 100%). Computed server-side as 10000² / minimumCollateralRatio (integer floor). Null when the facility does not enforce a collateral requirement."},"totalOutstandingDebt":{"type":"string","nullable":true,"description":"Total outstanding debt in USD as a formatted decimal string with trailing zeros trimmed (e.g. \"1234.56\"). The debt token's decimals are read from the first active credit position and applied server-side. \"0\" when there are no active positions. Null when the facility does not enforce a collateral requirement."},"collateralValue":{"type":"string","nullable":true,"description":"Collateral value in USD as a formatted decimal string with trailing zeros trimmed (e.g. \"2000\" or \"1999.99\"). Formatted server-side. Null when the facility does not enforce a collateral requirement."},"ltvBps":{"type":"string","nullable":true,"description":"Current loan-to-value ratio in basis points: (totalOutstandingDebt × 10000) / collateralValue, computed server-side from raw on-chain values (decimals normalized before division). \"0\" when there is no outstanding debt. \"999999999\" (sentinel) when debt is positive but on-chain collateral value is 0 — the facility is effectively infinitely undercollateralized. Null when the facility does not enforce a collateral requirement, or when debt decimals could not be resolved."},"targetLtvBps":{"type":"string","nullable":true,"description":"Target LTV in basis points. Defines the minimum collateral value required to back the facility's credit limit (min collateral ≈ creditLimit × 10000 / targetLtvBps). Null when no target is configured for this facility."},"collateralTokens":{"type":"array","description":"Every token ever enabled as collateral on the Escrow, with its current on-chain amount and USD value. May be empty if EnableCollateral events have not been ingested for this Escrow.","items":{"type":"object","required":["address","amount","decimals","usdValue"],"properties":{"address":{"type":"string","description":"Collateral token address (ERC-20)."},"amount":{"type":"string","nullable":true,"description":"Current on-chain collateral amount (raw uint256; divide by `decimals` to get human-readable value). Null if the on-chain `getCollateralData` read failed."},"decimals":{"type":"integer","nullable":true,"description":"Decimals of the collateral token itself (for rendering `amount`). Null if ERC-20 metadata could not be fetched."},"usdValue":{"type":"string","nullable":true,"description":"USD value of the current collateral amount as a human-readable decimal string (e.g. \"1234.56\"), up to 6 decimal places with trailing zeros trimmed. Null if amount, price, or decimals is unavailable."}}}}}},"totals":{"type":"object","nullable":true,"description":"v3 only. Facility-level aggregates for the facility's single asset: native-unit amounts plus `creditLimitUsd` (the total credit limit in USD). Only included when expand includes \"totals\". Null for v1/v2 facilities — their credit lines can use different tokens, so a single-asset total (and one `decimals`) is not meaningful (use the USD totals on GET /v3/credit-facilities/{id}/credit-lines instead). Also null for a v3 facility when the on-chain read is unavailable; use protocolVersion to distinguish the two cases.","required":["totalCommitment","totalDrawn","drawnRate","undrawnRate","token","decimals","creditLimitUsd"],"properties":{"totalCommitment":{"type":"string","nullable":true,"description":"The facility's total committed credit across its active credit lines, raw uint256 — divide by 10^decimals for a human-readable value. Closed lines no longer count toward the commitment."},"creditLimitUsd":{"type":"string","nullable":true,"description":"The facility's total credit limit in USD — totalCommitment priced in `token` at request time, as a human-readable decimal string. Null when totalCommitment is null, decimals is unavailable, or the token is unpriced. (For v1/v2, use creditLimitUsd on GET /v3/credit-facilities/{id}/credit-lines instead.)"},"totalDrawn":{"type":"string","nullable":true,"description":"The facility's total drawn principal across its credit lines, raw uint256 — divide by 10^decimals for a human-readable value."},"drawnRate":{"type":"string","nullable":true,"description":"Facility-default draw rate in basis points (DRAWN_RATE_BPS) — interest on drawn principal. Individual commitments may override this; see each credit line's drawRate for the effective per-line rate. Null if the facility exposes no per-facility rate getter (e.g. TIERED)."},"undrawnRate":{"type":"string","nullable":true,"description":"Facility-default undrawn rate in basis points (UNDRAWN_RATE_BPS) — interest on the undrawn commitment. Individual commitments may override this; see each credit line's facilityRate for the effective per-line rate. Null if the facility exposes no per-facility rate getter (e.g. TIERED)."},"token":{"type":"string","nullable":true,"description":"The single ERC-20 asset every credit line in the facility is denominated in — the unit of totalCommitment and totalDrawn."},"decimals":{"type":"integer","nullable":true,"description":"Decimals of the facility asset (token), for formatting the raw amounts above."}}}}},"Organization":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string","format":"uuid","description":"Organization unique identifier"},"name":{"type":"string","maxLength":255,"description":"Organization display name"},"slug":{"type":"string","maxLength":100,"description":"URL-friendly identifier"},"header":{"type":"string","nullable":true,"description":"Short tagline or headline for the organization profile"},"description":{"type":"string","nullable":true,"description":"Brief summary of the organization"},"overview":{"type":"string","nullable":true,"description":"Long-form organization description (may contain Markdown)"},"links":{"type":"array","description":"Organization links and image assets. Labels starting with \"#\" are image assets (e.g. \"#logo\", \"#header\"); all others are external links (e.g. \"Twitter\", \"Website\").","items":{"type":"object","required":["id","label","url"],"properties":{"id":{"type":"string","format":"uuid","description":"Link unique identifier"},"label":{"type":"string","description":"Link type. \"#logo\" and \"#header\" denote image assets; other values (e.g. \"Twitter\", \"Website\") denote external links."},"linkText":{"type":"string","nullable":true,"description":"Display text for external links (e.g. \"@raincards\", \"rain.xyz\")"},"iconUrl":{"type":"string","nullable":true,"description":"Icon image URL for external links"},"url":{"type":"string","description":"Target URL (image URL for asset links, destination URL for external links)"}}}}}}}}}
```

## The CreditLine object

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"components":{"schemas":{"CreditLine":{"type":"object","required":["lineTokenId"],"properties":{"lineTokenId":{"type":"string","description":"Credit line token ID"},"deposit":{"type":"string","nullable":true,"description":"Deposit amount (raw uint256 — divide by 10^decimals to get human-readable value)"},"creditLimit":{"type":"string","nullable":true,"description":"Credit limit (raw uint256 — divide by 10^decimals to get human-readable value). For open lines: equals current deposit. For closed lines: deposit from the most recent AddCredit or IncreaseCredit event."},"principal":{"type":"string","nullable":true,"description":"Principal amount borrowed (raw uint256 — divide by 10^decimals to get human-readable value)"},"interestBalance":{"type":"string","nullable":true,"description":"Total interest held by the credit line: the sum of interestAccrued and interestRepaid (raw uint256 — divide by 10^decimals to get human-readable value). v3: equals interestAccrued (repaid proceeds are reported via the claimable field)."},"interestAccrued":{"type":"string","nullable":true,"description":"Interest accrued and owed by the borrower but not yet repaid (raw uint256 — divide by 10^decimals to get human-readable value). v3: equals interestBalance."},"interestRepaid":{"type":"string","nullable":true,"description":"Interest already repaid into the credit line and held for the lender to claim/withdraw (raw uint256 — divide by 10^decimals to get human-readable value). Null for v3 — repaid proceeds are reported in aggregate (principal + interest) via the claimable field."},"token":{"type":"string","nullable":true,"description":"Token address for this credit line"},"decimals":{"type":"integer","nullable":true,"description":"Token decimals"},"isOpen":{"type":"boolean","nullable":true,"description":"Whether the credit line is open"},"isRestricted":{"type":"boolean","nullable":true,"description":"Whether the credit line is restricted. Null for v3 (no equivalent)."},"earlyWithdrawalFee":{"type":"string","nullable":true,"description":"Early withdrawal fee in basis points. Null for v3 (no equivalent)."},"deadline":{"type":"string","format":"date-time","nullable":true,"description":"Credit line deadline"},"drawRate":{"type":"string","nullable":true,"description":"Draw rate in basis points (interest rate on borrowed principal)"},"facilityRate":{"type":"string","nullable":true,"description":"Facility rate in basis points (interest rate on unused deposit)"},"apyPct":{"type":"number","nullable":true,"description":"Computed APY as a percentage (e.g. 5.0 = 5.0%). Weighted average of drawRate on principal and facilityRate on unused deposit."},"createdTxHash":{"type":"string","nullable":true,"description":"Transaction hash of the AddCredit event that created this line"},"createdBlockNumber":{"type":"integer","nullable":true,"description":"Block number when this credit line was created"},"createdAt":{"type":"string","format":"date-time","nullable":true,"description":"Timestamp when this credit line was created. May be null for refinanced commitments."},"commitmentValue":{"type":"string","nullable":true,"description":"v3 only. Canonical par value of the commitment (drawn + interestOwed + claimable + undrawn residual), raw uint256. Null for v2. As of the last on-chain accrual checkpoint."},"claimable":{"type":"string","nullable":true,"description":"v3 only. Repaid/closed proceeds currently claimable by the commitment owner, raw uint256. Null for v2."},"facilityType":{"type":"string","nullable":true,"description":"v3 only. Facility type (\"RCF\" | \"TLA\" | \"DDTL\" | \"TIERED\"). Null for v2."},"isDefaulted":{"type":"boolean","nullable":true,"description":"v3 only. Cross-default (impairment) flag for the position's borrower. Null for v2."},"priority":{"type":"string","nullable":true,"description":"v3 only. Repayment-queue seniority of this commitment (raw uint256; the on-chain terms.priority). Sort by it client-side if you need a strict seniority ordering — the array is not guaranteed to be priority-sorted. Closed lines report `0` (on-chain storage is cleared on close), so drop closed lines before sorting. Null for v1/v2."},"fees":{"type":"object","nullable":true,"description":"Only included when expand=fees is specified. Null if fetching failed.","required":["originationFees"],"properties":{"originationFees":{"type":"string","nullable":true,"description":"Origination fees for this credit line (raw uint256 — divide by 10^decimals to get human-readable value). Null if unavailable."}}},"error":{"type":"string","nullable":true,"description":"Error message if fetching this credit line failed. Other fields will be null."}}}}}}
```

## The Servicing object

```json
{"openapi":"3.0.3","info":{"title":"Credit Coop API","version":"3.0.0"},"components":{"schemas":{"Servicing":{"type":"object","required":["id","address","networkId","organizationId"],"properties":{"id":{"type":"string","format":"uuid","description":"Servicing unique identifier"},"address":{"type":"string","description":"Servicing contract address"},"networkId":{"type":"string","description":"CAIP-2 network identifier"},"organizationId":{"type":"string","format":"uuid","nullable":true,"description":"Borrower organization ID"},"status":{"type":"object","nullable":true,"description":"On-chain cross-default health of the servicing. Only included when expand includes \"status\".","required":["closed","isDefaulted","breachLevel"],"properties":{"closed":{"type":"boolean","nullable":true,"description":"Whether the servicing has been wound down (terminal). Null when unavailable."},"isDefaulted":{"type":"boolean","nullable":true,"description":"Whether the borrower is in cross-default — one covenant breach gates every facility under this servicing. Null when unavailable."},"breachLevel":{"type":"string","nullable":true,"enum":["NONE","CURING","DEFAULTED"],"description":"Worst covenant breach level across the servicing. Null when it cannot be determined."}}},"asset":{"type":"object","nullable":true,"description":"The accounting unit every raw amount on this servicing (collateral value, capacity) is denominated in. Only included when expand includes \"asset\".","required":["token","decimals"],"properties":{"token":{"type":"string","nullable":true,"description":"Address of the accounting asset. Null when the servicing has no facilities yet or it could not be resolved."},"decimals":{"type":"integer","nullable":true,"description":"Decimals of the accounting asset — divide any raw uint256 amount by 10^decimals to get a human-readable value. Null when unavailable."}}},"organization":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/Organization"}],"description":"Organization details with links. Only included when expand includes \"organization\"."},"relatedAddresses":{"type":"object","nullable":true,"description":"Servicer (owner), borrower, and trustee addresses. Only included when expand includes \"related-addresses\".","required":["owner","borrower","trustee"],"properties":{"owner":{"type":"string","nullable":true,"description":"The servicer — the owner of this Servicing hub (gates servicing actions). Distinct from the borrower and trustee."},"borrower":{"type":"string","nullable":true,"description":"The borrower this servicing serves."},"trustee":{"type":"string","nullable":true,"description":"Recipient of seized collateral on liquidation."}}},"collateral":{"type":"array","nullable":true,"description":"The shared collateral pool, one entry per registered collateral. Only included when expand includes \"collateral\".","items":{"type":"object","required":["address","advanceRateBps","value","decimals","valueUsd","level","asset","collateralToken","released","owner"],"properties":{"address":{"type":"string","description":"Collateral contract address."},"advanceRateBps":{"type":"integer","nullable":true,"description":"Share of this collateral's value that counts toward the borrowing base, in basis points (10000 = 100%). Null if unavailable."},"value":{"type":"string","nullable":true,"description":"Raw mark-to-market value (uint256) denominated in `asset` — divide by 10^`decimals` for the human amount. Null if unavailable."},"decimals":{"type":"integer","nullable":true,"description":"Decimals of `asset` — the shared precision of `value` and `valueUsd`. Null when the denomination could not be determined, or when `asset` is known but its on-chain `decimals()` read failed."},"valueUsd":{"type":"string","nullable":true,"description":"USD value as a human-readable decimal string, priced in `asset`. This is the correct number for the LTV sum (the server picks the right per-collateral token). Null when `asset` is unpriced or the denomination could not be determined."},"level":{"type":"string","nullable":true,"enum":["NONE","CURING","DEFAULTED"],"description":"Breach level reported by this collateral. Null if unavailable."},"asset":{"type":"string","nullable":true,"description":"The ERC-20 token that `value` and `valueUsd` are denominated in (so `asset`, `value`, `decimals`, and `valueUsd` are all mutually consistent). For a normal deposited-token collateral this is the same as `collateralToken`. It differs only for a revenue collateral, whose `value` is a fixed appraisal expressed in the facility's accounting unit rather than in the revenue token it collects — there `asset` is that accounting unit. Null when the denomination could not be determined."},"collateralToken":{"type":"string","nullable":true,"description":"The collateral's underlying on-chain token — use this for a \"Token\" column. For a deposited-token collateral it is the escrowed token; for a revenue collateral it is the token the revenue is paid in. Null for a collateral that pledges a contract rather than a token. Usually equals `asset`; it differs only for a revenue collateral (valued in the accounting unit, not the revenue token) — in that case use `valueUsd`/`asset`/`decimals` for the numbers and `collateralToken` only for display."},"released":{"type":"boolean","nullable":true,"description":"Whether this collateral has been released. A released collateral no longer backs the borrowing base, so exclude it when summing `valueUsd` into a collateral-coverage total (its `valueUsd` is still reported). Null if unavailable."},"owner":{"type":"string","nullable":true,"description":"The escrow owner that gates deposit/withdraw actions. Null if unavailable."}}}},"facilities":{"type":"array","nullable":true,"description":"The facilities bound to this servicing. Only included when expand includes \"facilities\".","items":{"type":"object","required":["address","facilityId","organizationId"],"properties":{"address":{"type":"string","description":"Facility contract address."},"facilityId":{"type":"string","format":"uuid","nullable":true,"description":"Resource ID of the facility (use with GET /v3/credit-facilities/:id). Null when the facility address is not registered."},"organizationId":{"type":"string","format":"uuid","nullable":true,"description":"Organization ID of the facility, when registered."}}}},"capacity":{"type":"object","nullable":true,"description":"Shared borrowing-base aggregates across every facility. Only included when expand includes \"capacity\". All amounts are raw uint256 in the accounting unit — divide by 10^decimals.","required":["totalAdvancedValue","totalDrawn","totalCommitted","remainingDrawCapacity","remainingOriginationCapacity"],"properties":{"totalAdvancedValue":{"type":"string","nullable":true,"description":"The shared borrowing base. Null if unavailable."},"totalDrawn":{"type":"string","nullable":true,"description":"Total drawn across all facilities. Null if unavailable."},"totalCommitted":{"type":"string","nullable":true,"description":"Total committed across all facilities. Null if unavailable."},"remainingDrawCapacity":{"type":"string","nullable":true,"description":"Borrowing base remaining for new draws (floored at 0). Null when an input is unavailable."},"remainingOriginationCapacity":{"type":"string","nullable":true,"description":"Borrowing base remaining for new originations (floored at 0). Null when an input is unavailable."}}},"covenants":{"type":"array","nullable":true,"description":"Per-covenant breach levels behind the cross-default status. Only included when expand includes \"covenants\".","items":{"type":"object","required":["address","level","cureWindow"],"properties":{"address":{"type":"string","description":"Covenant contract address."},"level":{"type":"string","nullable":true,"enum":["NONE","CURING","DEFAULTED"],"description":"Breach level for this covenant. Null if unavailable."},"cureWindow":{"type":"string","nullable":true,"description":"Grace period in seconds before a breach escalates from CURING to DEFAULTED. Null if unavailable, or for a collateral entry (collaterals also appear here but expose no cure window)."}}}}}},"Organization":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string","format":"uuid","description":"Organization unique identifier"},"name":{"type":"string","maxLength":255,"description":"Organization display name"},"slug":{"type":"string","maxLength":100,"description":"URL-friendly identifier"},"header":{"type":"string","nullable":true,"description":"Short tagline or headline for the organization profile"},"description":{"type":"string","nullable":true,"description":"Brief summary of the organization"},"overview":{"type":"string","nullable":true,"description":"Long-form organization description (may contain Markdown)"},"links":{"type":"array","description":"Organization links and image assets. Labels starting with \"#\" are image assets (e.g. \"#logo\", \"#header\"); all others are external links (e.g. \"Twitter\", \"Website\").","items":{"type":"object","required":["id","label","url"],"properties":{"id":{"type":"string","format":"uuid","description":"Link unique identifier"},"label":{"type":"string","description":"Link type. \"#logo\" and \"#header\" denote image assets; other values (e.g. \"Twitter\", \"Website\") denote external links."},"linkText":{"type":"string","nullable":true,"description":"Display text for external links (e.g. \"@raincards\", \"rain.xyz\")"},"iconUrl":{"type":"string","nullable":true,"description":"Icon image URL for external links"},"url":{"type":"string","description":"Target URL (image URL for asset links, destination URL for external links)"}}}}}}}}}
```


# Important Legal Notice

Do not use the Services (as defined in our Terms of Use ("Terms")) if you are not an expert in Digital Assets and blockchain technology. By using the Services, you shall be deemed to have read the Terms in full and to agree to be bound by them.

CMBT Labs Inc. is the development company ("DevCo") for the Credit Coop Protocol. CMBT Labs provides a software interface and tooling layer that enables interaction with independent smart contracts and protocol components. CMBT Labs does not operate the Credit Coop Protocol, make lending or credit decisions, or act as a lender, broker, investment adviser, or financial intermediary. The Credit Coop Protocol is stewarded and operated by Lockbox Foundation, a Cayman Islands foundation company, which is not a party to the Terms.

The Services are provided "as is" and "as available," without any representation or warranty of any kind, whether express, implied, or statutory.  CMBT Labs expressly disclaims all warranties, including any implied warranties of merchantability, fitness for a particular purpose, title, and non-infringement.

Transactions involving Digital Assets entail substantial risk, including the risk of total loss. CMBT Labs expressly disclaims all liability for any claims, damages, losses, or expenses of any kind arising from or related to your use of, or inability to use, the Services.&#x20;

Access to the Services is strictly limited to Accredited Investors, Professional Investors, and Qualified Participants as defined under applicable law. The Services are not available to retail or consumer investors.

By accessing or using the Services, you are entering into a binding agreement with CMBT Labs that includes the Terms and Privacy Policy. If you do not agree, you must not use the Services.\
\
All notices and legal enquiries: <legal@creditcoop.xyz>


# Terms of Use

Please find attached our Terms of Use.  Acceptance of the Terms of Use is a pre-requisite to using the Services.

{% file src="/files/AHSiVMvTz6IlxNt6JnVd" %}


# Privacy Policy

Please find attached our Privacy Policy. Acceptance of the Privacy Policy is a pre-requisite to using the Services.

{% file src="/files/tZsvSSh0VSpVJzGfLTFw" %}


