# How Turtle works
Source: https://docs.turtle.xyz/get-started/how-turtle-works
The flow from a liquidity provider deposit through on-chain attribution to distributor revenue and protocol incentives.
Turtle is infrastructure between DeFi yield opportunities and the platforms that distribute them. The clearest way to understand it is to follow a single deposit from start to finish.
This page is for a partner deciding whether and how to integrate Turtle, and it traces the full flow so you can see where your product plugs in.
## The flow
A distributor picks which vaults to show its users and links them to the deposit page, either through a no-code [share link](/partner-products/share-links) or a full [API integration](/sdk/earn/deposit). Each link or transaction carries the distributor's ID.
The LP deposits into the vault from their own wallet. The vault is one of many in the catalog, each reviewed before listing. The LP signs and submits the transaction; Turtle never takes custody.
The distributor's ID is embedded in the deposit calldata. Turtle monitors every supported chain and links the deposit to the distributor that sourced it. There is no manual reporting step.
The LP earns the vault's base yield. On a featured opportunity (or Turtle Deal), the LP also earns extra token emissions funded by the protocol, distributed through Turtle's incentive products.
Because the deposit is attributed, the distributor earns recurring revenue share on the TVL it brought, for as long as that TVL stays. Protocols are billed on attributed TVL, so they pay only for liquidity Turtle delivered.
## The pieces that run the flow
The same flow runs through a small set of products, each handling one part of the loop.
**Earn** is the distribution layer. It gives a distributor access to the full vault catalog through one integration, generates the deposit and withdrawal transactions, and tracks attributed activity, all scoped to a single distributor ID. It powers [Distribution](/partner-products/distribution/overview), the partner product built on top of it.
**Yield Opportunities** are the opportunities themselves. An LP deposits, holds, and withdraws; some vaults settle instantly and some settle asynchronously. See [Yield Opportunities](/liquidity-products/turtle-vaults).
**Streams** are how a protocol attaches extra incentives to a vault. A [Stream](/partner-products/streams/overview) is a self-serve reward campaign that pays LPs in proportion to their TVL.
**Liquidity Campaigns** define Turtle-selected opportunities that pass Turtle Due Diligence Council review and often include additional incentives to attract investors. A [Liquidity Campaign](/liquidity-products/turtle-deals) is a selected series of vaults, often with additional incentives funded by a protocol treasury.
**Swaps** let an LP deposit from almost any EVM token into any supported vault, with routing handled inside the deposit flow.
## Attribution and revenue share
Attribution is what makes the loop pay. Every deposit is linked on-chain to the distributor that sourced it, automatically, with no trusted reporting in between. Distributors earn recurring revenue share on attributed TVL, and the same on-chain record is what protocols are billed against. The full attribution mechanism for engineers lives in the [distributor model](/sdk/concepts/distributor-model).
## The diligence standard
Opportunities on Turtle are not self-listed. Each vault goes through a structured review before a distributor can surface it. The review covers technical risk, smart contract exposure, operational risk, and curator assessment. See [Trust and Security](/get-started/trust-and-security) for how that review and the custody model protect LPs.
# Trust and Security
Source: https://docs.turtle.xyz/get-started/trust-and-security
How Turtle protects user assets: a non-custodial architecture, structured diligence, and independent audits.
The short answer: Turtle never holds your funds. It is non-custodial by design, every opportunity is reviewed before it reaches the catalog, and the contracts are independently audited. The rest of this page explains each of those.
If you are deciding whether to move funds through Turtle, this page explains exactly what Turtle can and cannot do with your assets.
## Turtle never takes custody
You keep full control of your assets at every step. Turtle generates an unsigned transaction; you sign and submit it from your own wallet. No private keys are ever shared with or accessible by Turtle, and there is no point in the flow where Turtle can move, hold, or freeze your funds.
When you deposit, your assets go into the vault contract you chose, not to Turtle. When you withdraw, they come back to your wallet directly.
## Every opportunity is reviewed first
Opportunities on Turtle are not self-listed. Before a vault reaches the catalog, the Turtle Due Diligence Council reviews it across technical risk, smart contract exposure, operational risk, and curator assessment, and publishes a diligence report for each featured vault.
The review body, its four risk dimensions, and how it stays independent.
## The contracts are audited
Turtle's smart contracts have been audited by independent security firms. The Streams contract system was audited by [Cantina](https://cantina.xyz) in January 2026, and further audits cover the Drip contract and core protocol infrastructure.
Full audit reports for the Streams, Drip, and core contracts.
## Featured vaults are proven solvent
Turtle's featured vaults are independently verified by [Accountable](https://accountable.finance), an on-chain solvency verification provider. Each verification confirms that reported TVL matches actual on-chain holdings, so the numbers you see are checked against the chain, not self-reported.
## What Turtle never controls
Turtle does not custody assets, does not hold private keys, and cannot move or freeze your funds. It does not control the underlying vault or its yield, which come from the vault's own contracts and curator. Turtle's role is to surface reviewed opportunities, generate transactions you sign yourself, and attribute deposits.
# What is Turtle?
Source: https://docs.turtle.xyz/get-started/what-is-turtle
Turtle is a distribution protocol that connects DeFi yield opportunities with the partners and platforms that distribute them.
Turtle is a distribution protocol for DeFi yield. It sits at the center of a three-sided marketplace and matches the sides to each other.
On one side are yield opportunities: a broad catalog of vaults across major EVM chains, each reviewed before it reaches the catalog. On a second side are the distributors that surface those opportunities to end users, including wallets, exchanges, neobanks, and other platforms that integrate once and route their users into vaults. On the third side are the protocols that want liquidity and are willing to pay to attract it. Distributors bring the users, protocols fund the incentives, and liquidity providers earn the yield.
Attribution holds the triangle together. Every deposit is linked on-chain to the distributor that sourced it, so distributors earn recurring revenue share on the TVL they bring and protocols pay only for liquidity Turtle actually delivered. A large and growing base of wallets has registered through the network, and users keep custody of their assets at every step.
A **distributor** is any partner that routes users into Turtle opportunities and is credited for the deposits. A **vault** is a yield position in the catalog that an LP deposits into. See the [glossary](/resources/glossary) for the full vocabulary.
## Who operates Turtle
The protocol is operated by the **Turtle.Club Association**, a Swiss *Verein* seated in Zug, Switzerland, that executes governance decisions on behalf of TurtleDAO. The [Terms of Service](/legal/terms) are governed by Swiss law, and disputes are handled by the ordinary courts at the seat of the Association.
## External links
* [Website](https://turtle.xyz)
* [App](https://app.turtle.xyz)
* [Client Portal](https://dashboard.turtle.xyz)
* [Audit Reports](/resources/audits)
* [X (Twitter)](https://x.com/turtledotxyz)
* [Discord](https://discord.turtle.xyz)
* [GitHub](https://github.com/turtle-dao)
* [LinkedIn](https://linkedin.com/company/turtleclub)
# Privacy Statement
Source: https://docs.turtle.xyz/legal/privacy-policy
Version 3.0 – July 9, 2026
## **1. About Us**
At Turtle, we believe privacy is a fundamental human right. This privacy policy (“Privacy Policy”) explains how we process and protect your personal data when you use this Website or the services provided via the Platform provided via [https://app.turtle.xyz](https://app.turtle.xyz) (together, the “Services”).
These Services are operated by Turtle DAO, orchestrated through the Turtle Association (the “Association”, “we”, “our”, or “us”), which is the controller for the data processing described below.
**What We Collect**
Account details, device identification, usage metrics, coarse region mapping, and organizational compliance, financial, and due diligence data.
**Core Purpose**
To facilitate fundraising activities and comply with Anti-Money Laundering (AML)/Know Your Customer (KYC) regulations, securely operate the platform, resolve software bugs, and satisfy global legal obligations.
**Your Rights & Controls**
Frictionless access, deletion, data porting, correction, and processing restrictions.
## **2. Categories of Personal Data We Collect**
To provide a seamless, secure user experience, we explicitly collect and organize personal data into the following categories:
* **Account Profile Information:** Legal name, validated email address, telephone contact number, and encrypted password metrics.
* **Technical & System Attributes:** Internet Protocol (IP) address, browser definitions, operating system details, device model identifiers, and detailed software crash telemetry.
* **Platform Usage Analytics:** Specific feature interactions, engagement timestamps, system navigation behaviors, and performance benchmarks.
* **Geographic Location:** Coarse, non-precise regional location extrapolated exclusively from IP addressing to enforce compliance parameters. We do not collect precise hardware GPS metrics.
* **Corporate & Due Diligence Information:** Details related to organizational structure, fundraising, and compliance, which may include the names, contact details, financial interests, and identity verification records (such as government IDs) of founders, directors, Persons with Significant Control (PSCs), and investors associated with the organization.
## **3. Sources of Personal Data (How We Collect Your Information)**
To maintain complete transparency in line with global regulations, Turtle gathers personal data through three primary mechanisms:
**A. Data You Direct to Us (Direct Collection):** We collect personal information that you manually enter or supply during your interactions with our ecosystem. This includes:
* Information provided when creating or verifying an account (e.g., name, email address, phone number).
* Data submitted when contacting Turtle support, participating in surveys, or requesting technical assistance.
* Corporate documentation, capitalization tables, and official identity verification credentials (such as government-issued identification) transmitted throughout institutional onboarding procedures, due diligence assessments, or capital-raising cycles. This encompasses personal metrics supplied regarding third-party individuals, including corporate directors, equity investors, or Persons with Significant Control (PSCs).
**B. Data Captured Electronically and Automatically (Passive Collection):** When you navigate or interact with Turtle platforms, our systems automatically log operational metrics. This includes:
* **Cookies and Tracking Technologies:** Unique identifiers, session states, and tracking pixels deployed within your browser or device interface.
* **System and Infrastructure Logs:** IP addresses, browser configurations, internet service provider (ISP) details, entry/exit pages, timestamps, and crash telemetry records.
**C. Data Acquired from Third Parties (External Sourcing):** Turtle may occasionally receive data about you from external commercial partners. This includes:
* **Identity & Fraud Prevention Services:** Vendors utilized to verify user age, validate regional compliance, or detect malicious platform actors.
* **Analytics and Infrastructure Partners:** Services providing aggregate market metrics, software performance debugging data, or localized advertising conversion statistics.
* **Corporate Registries:** Openly accessible government databases and official repositories, such as Companies House, leveraged to authenticate corporate governance frameworks, legal entity architecture, and beneficial ownership status.
## **4. Cookies and Automated Tracking Technologies**
Turtle utilizes cookies, pixels, and localized script-based identifiers to optimize performance, preserve user preferences, and secure our infrastructure. In alignment with global frameworks, including the EU ePrivacy Directive, we categorize our automated tracking deployment into two clear operational tiers:
* **A. Strictly Necessary & Functional Cookies (Mandatory):** These tracking elements are mathematically required to operate the basic functions of Turtle. They handle secure session routing, identity authentication parameters during active logins, network load balancing, and anti-fraud server validation. The platform cannot function without these identifiers, and they do not track your behavior across external internet ecosystems.
* **B. Performance & Analytics Cookies (Optional):** We utilize first-party analytics tools to assess how users collectively interact with our software interfaces. This data is fully aggregated and pseudonymized, tracking software crashes, page latency, and interface feature engagement metrics. We use this data solely to improve system speed and usability. **Turtle does not deploy third-party tracking cookies or pixels for cross-context behavioral marketing or targeted advertising.**
### **How to Manage and Control Cookies**
Most web browsers are configured to accept cookies by default. You retain the right to modify your browser settings to reject, wipe, or block cookies entirely. However, because Strictly Necessary cookies are structurally tied to Turtle’s baseline operations, disabling them completely may result in platform failures, rendering account access inoperable.
To audit or disable your cookie preferences, please consult the "Help," "Tools," or "Privacy" menus within your specific browser application (such as Apple Safari, Google Chrome, or Mozilla Firefox).
## **5. Social Media and Links to Third-Party Apps and Websites**
Our Services contain links to websites or apps that are not operated by us. When you click on a third-party link, you will be directed to that third party’s website or app. We have no control over the content, privacy policies, or practices of any third-party websites or services.
We maintain online presences on social networks to, among other things, communicate with customers and prospective customers and to provide information about our products and Services. If you have an account on the same network, it is possible that your information and media made available there may be seen by us, for example, when we access your profile. In addition, the social network may allow us to contact you. As soon as we transfer personal data into our own system, we are responsible for this independently. This is then done to carry out pre-contractual measures and to fulfil a contract. For the legal basis of the data processing carried out by the social networks under their own responsibility, please refer to their data protection declarations.
## **6. Lawful Bases for Data Processing (GDPR/UK GDPR Compliance)**
For users operating within the European Economic Area (EEA) and the United Kingdom, all processing activities are paired with an explicit legal basis defined under Article 6 of the GDPR:
| **Processing Operation** | **Data Categories Involved** | **GDPR Lawful Basis** |
| :-------------------------------------------------------------------------- | :-------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| User profile deployment and identity validation | Account Profile Information | Performance of a Contract (Article 6(1)(b)) |
| Platform optimization and interface bug resolution | Technical Attributes, Usage Analytics | Legitimate Interests (Article 6(1)(f)) to refine service delivery |
| Malicious activity mitigation and network defense | Technical Attributes, Account Profile | Legal Obligation (Article 6(1)(c)) and Legitimate Security Interests |
| Corporate due diligence, KYC/AML verification, and fundraising facilitation | Corporate and Due Diligence Information | Legal Obligation (Article 6(1)(c)) for statutory anti-money laundering checks, and Legitimate Interests (Article 6(1)(f)) for assessing organizational viability and facilitating capital allocation. |
## **7. Statutory California Consumer Disclosures (CCPA/CPRA)**
In accordance with the California Consumer Privacy Act as amended by the CPRA, this section provides a retroactive 12-month lookback of personal information collected and disclosed for standard business operations:
| **Statutory CCPA Category** | **Data Elements Collected** | **Disclosed for Business Operations?** |
| :-------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------- |
| A. Identifiers | Legal name, email identity, unique IP addresses, account credentials, government-issued identification (e.g. passports, driver’s licenses) | Yes, shared exclusively with infrastructure and security providers |
| B. Commercial Data | Transaction history metrics, platform acquisition records, capitalization tables, equity ownership, and corporate fundraising history | Yes, shared with authorized payment merchant services |
| F. Network Activity | System navigation log, clickstream records, software feature interactions | Yes, shared with server monitoring and diagnostics platforms |
| G. Geolocation Data | Coarse regional location (City/State/Country level) extrapolated exclusively via IP addresses. | Yes, used internally for regional compliance routing and security validation |
**Sensitive Personal Information:** We collect government-issued identifiers (such as passports and driver's licenses) which are classified as Sensitive Personal Information under the CPRA. We use this data strictly for legally permitted purposes (such as KYC/AML identity verification) and do not use it to infer characteristics about consumers
**Selling or Sharing Prohibitions:** Turtle does not sell your personal information. Furthermore, Turtle does not "share" personal identifiers for cross-context behavioral or targeted advertising models as defined by California statutes.
## **8. Global Data Subject Rights & Control Protocols**
We extend core data autonomy protections universally to all users, matching international privacy standards:
* **Right of Verification & Access:** The right to demand confirmation of processing and obtain a complete copy of raw data files held by us.
* **Right of Correction:** The right to modify out-of-date, incomplete, or broken account parameters.
* **Right of Total Erasure (Deletion):** The right to request the permanent deletion of files, except where financial reporting or statutory hold regulations require data retention.
* **Right of Portable Export:** The right to download your file system in a clean, machine-readable format for transition elsewhere.
* **Right to Object & Restrict:** The right to halt data use for targeted updates or pause handling due to personal disputes.
* **Statutory Right to Non-Discrimination:** We strictly guarantee that exercising any choice under this policy will never result in service degradation, billing increases, or feature limits.
## **8.1 Verification Procedures and Operational Timelines**
To protect your privacy and maintain platform security, Turtle enforces strict operational protocols when processing data subject requests:
* **Submission Mechanics:** You may initiate a formal rights request by contacting us at: [info@turtle.xyz](mailto:info@turtle.xyz).
* **Identity Verification Protocol:** Upon receiving a request to access, correct, or delete personal data, Turtle must verify your identity before taking action. We will ask you to provide at least two to three pieces of personal identifiers that match information already maintained in our secure production environments (e.g., confirming the account email and recent account transaction dates). We will never disclose or delete data if we cannot establish identity to a reasonable or high degree of certainty.
* **Authorized Agents (California Residents):** You may designate an authorized agent to submit requests on your behalf. To do so, you must provide the agent with signed, written permission, or a valid Power of Attorney. The agent must verify their own identity directly with us, and we reserve the right to confirm the agent's authority directly with the account owner.
* **Response Timelines:** Turtle acknowledges all received requests within ten (10) business days. For residents of the EEA and UK, we provide substantive responses within thirty (30) days. For California residents, we resolve requests within forty-five (45) days. If a request is highly complex, we reserve the right to extend these timelines as permitted by local law, providing you with an explicit justification for the delay.
## **9. Data Minimization, Retention, & Destruction**
Personal data is stored exclusively for the baseline timeframe necessary to complete the functional operations outlined in Section 6, unless explicit statutory directives (such as corporate accounting and Anti-Money Laundering (AML) laws) mandate an extended preservation window. Upon the conclusion of a designated retention timeline, files are permanently wiped from production nodes or fully scrubbed via advanced anonymization methodologies to block any future re-identification risks.
## **10. Data Security and Safeguarding Measures**
Turtle is committed to protecting your personal data from unauthorized access, alteration, disclosure, or destruction. We utilize a multi-layered defense strategy comprising technical, administrative, and physical safeguards:
* **Technical Safeguards:** We deploy industry-standard encryption protocols. Data is encrypted while in transit across public networks using Transport Layer Security (TLS/HTTPS) and encrypted at rest on our secure cloud architecture using advanced encryption standards (such as AES-256). We routinely perform system vulnerability scanning and automated patch management to mitigate emerging software threats.
* **Organizational Safeguards:** We enforce strict "least-privilege" access controls. Internal access to your personal information is restricted exclusively to authorized Turtle employees, contractors, and agents who require that data to execute designated operational functions (Section 6). These individuals are bound by strict, legally enforceable confidentiality obligations.
* **Your Responsibility for Security:** Security is a shared responsibility. We strongly urge you to take every precaution to protect your personal data when navigating the internet. This includes using a unique, complex password for your Turtle account, keeping your authentication credentials strictly confidential, and ensuring your devices utilize updated software and security protections.
*Please note: While we continuously review and reinforce our protective perimeters, no method of digital transmission or electronic storage is 100% impenetrable. Consequently, Turtle cannot guarantee absolute security, and users interact with the platform acknowledging these baseline risks.*
## **11. Cross-Border Data Transfers**
To ensure reliable global access, platform operations utilize international cloud infrastructure networks. For data originating within jurisdictions like the EU or UK that is subsequently routed to regions lacking native adequacy status, Turtle deploys European Commission-approved Standard Contractual Clauses (SCCs) to mandate an unbroken perimeter of data defense.
## **12. Protection of Minors (Children's Privacy)**
Platform access is restricted to individuals who have reached 18 years of age. Turtle does not knowingly gather, verify, or archive personal metrics relating to minors under 18. If a parent or guardian establishes that a minor has bypassed security checks to supply data, please contact our team immediately for prompt, systemic removal of the data footprint.
## **13. Privacy Governance & Contact Information**
We maintain an internal Data Protection Officer (DPO) to manage our global alignment framework. For explicit rights enforcement actions, standard inquiries, or operational complaints, contact us directly: [info@turtle.xyz](mailto:info@turtle.xyz)
# Terms
Source: https://docs.turtle.xyz/legal/terms
Version 2.0 – [02 March 2025]
## **1. Introduction and scope**
Welcome to [turtle](http://turtle.xyz), a distribution platform aimed to align incentives among liquidity providers, protocols and other players in the DeFi space. These general terms and conditions (the "Terms") apply to your (the "Member(s)" and the "Partner Protocol(s)" or in each case "you") access or use of the [Turtle](http://turtle.xyz) platform available through [https://app.turtle.xyz/](https://app.turtle.xyz/) (the "Platform") provided by the [Turtle](http://turtle.xyz) DAO ("DAO") through the orchestration of the [Turtle](http://turtle.xyz) association ("Association").
Your access or use of the Platform constitutes consent to these Terms, each time you do so. If you do not accept or comply with these Terms in full and without restriction or limitation, you may not access or use the Platform. YOUR ACCEPTANCE TO THESE TERMS IS INCLUDED IN YOUR SIGNATURE WHEN CONNECTING YOUR WALLET TO THE PLATFORM.
Important notice: No access or use of the Platform is offered for Prohibited Use and/or to Excluded Persons, as further outlined in these Terms. Use of a virtual private network (VPN) to circumvent any restrictions under these Terms or under applicable laws is strictly prohibited.
## **2. Platform**
### **2.1 Services**
Through the Platform, you may, subject to your Eligibility as per section 2.2, access a variety of services, including but not limited to the services outlined below (the "Services"). You acknowledge and agree that such Services may from time to time be changed or discontinued without prior notification.
* **Tracking**: The Platform may allow Members to track their on-chain activity with integrated Partner Protocols. Connecting your Wallet authorizes the Platform to assign you to a specific Partner Protocol as a referral and track your on-chain activity with integrated Partner Protocols. This enables the Platform to facilitate liquidity distribution and may, from time to time, allow to distribute incentives associated to Member activity through the Platform or else ("**Rewards**"). You acknowledge and agree that:
* The distribution of any such Rewards is entirely subject to change in connection with the technical and governance parameters of the Platform and the DAO and you do not have any sort of legal right or claim towards any sort of Rewards; and
* such Rewards constitute a remuneration for your services that you may provide to those Partner Protocols (subject to the rules of such Partner Protocol) and are not any sort of capital flow due to an investment, participation or similar in [turtle](http://turtle.xyz).
* **Plugin solution**: The Platform may provide a plug-in that enables Partner Protocols to create customizable sites on their own platforms. This feature allows Partner Protocols to showcase other Partner Protocols within the Platform's network and offer potential Reward opportunities available through those Partner Protocols. You understand and acknowledge that any Rewards resulting from interactions with a Partner's site, including opportunities for potential Rewards, is subject to the terms and conditions of the respective Partner Protocol. The Platform is not responsible for any losses or damages incurred in connection with the use of Partner Protocol sites or the potential Reward opportunities they offer.
* **Frontend to Vaults**: The Platform may provide an interface ("Frontend") for facilitated interaction with decentralized, non-custodial, on-chain smart contracts to deposit and withdraw digital assets (such smart contract a "Vault").
**With respect to Vaults, you acknowledge and understand that** Vaults are not provided or operated by the DAO and/or the Association, but by independent third-party curators who provide and curate Vaults on their own behalf.
You may view information for each of those Vaults, whereby the information displayed is subject to change and adjustment. You are responsible for carrying out your own due diligence before choosing a Vault, and for monitoring any changes made to the Vault over time. You may decide a Vault to supply liquidity to, at your sole discretion and risk. Neither the DAO nor the Association are liable for any losses or damages incurred in connection with the use of these Vaults.
**With respect to the Frontend, you acknowledge and understand that** the Frontend is an off-chain interface that facilitates your interaction with underlying smart contracts, whereby the functionalities of the Frontend are limited to visualizing information obtained from the smart contracts and propose interactions based entirely on your own inputs. The Vaults are entirely separate from the Frontend and remain unaffected from any changes to the Frontend. By controlling the Frontend, the DAO and/or the Association does not exercise any control whatsoever over any functionalities of the Vaults or over any assets you may place in a Vault.
### **2.2 Eligibility**
Each time you access and use the Platform, you acknowledge, confirm, and agree to all of the following:
* You satisfy and comply with all legal and regulatory requirements according to any laws and regulations applicable to you concerning the access and use of the Platform and any other actions as may be contemplated under these Terms. Furthermore, you are of legal age according to applicable laws, and, if you are acting on behalf of a legal person, the legal entity is duly incorporated and you have the legal capacity and authority to enter into these Terms on behalf of such legal person.
* You may not access and use the Platform for any Prohibited Use (section 5.1). Furthermore, you may not access and use the Platform if you are an Excluded Person (section 5.2). Your compliance with the aforementioned may be technically monitored and enforced through the use of e.g., geo blocks, automated reconciliation of your Wallet against sanction lists and similar measures, to which you explicitly agree when accessing and using the Platform. There are no exceptions to the aforementioned restrictions, you may not (attempt) to circumvent any such restrictions and you may be excluded from the access and use of the Platform if you do not comply with these restrictions or you (attempt to) circumvent any such restrictions.
* To access and use the Platform, you must connect a compatible blockchain address through the use of a third-party wallet software ("**Wallet**"). You acknowledge and agree that the use of such Wallet may be subject to terms and conditions of respective third-parties, to which neither the DAO nor the Association have any relationship whatsoever. No Wallets are associated with, maintained by, supported by, affiliated with, or endorsed, and neither the DAO nor the Association assumes any liability or responsibility whatsoever in connection with your use of any Wallets. You are solely responsible for implementing reasonable measures to secure access to the Wallet (i.e., private key(s) or other credentials) used to interact with the Platform or receive, hold, send, and use TURTLE.
By connecting your Wallet, you must sign an on-chain message used to place a tracker on your Wallet, to verify ownership of your Wallet and accept these Terms. By connecting, you do not grant access or control over any assets in connection with your Wallet at any point. You acknowledge and agree that such connection is entirely at your own risk, and while there have been reasonable efforts to ensure that such connection is safe to use, you understand, acknowledge and agree that there might still be technical vulnerabilities, bugs, hacks or similar that may result in you losing assets or incurring damages and/or cause other negative consequences for you. The DAO/Association is not liable to you for any and all such negative consequences.
* You are solely legally entitled to any assets on, and you are solely legally responsible for any actions associated with, the Wallet. Furthermore, you access and use the Platform entirely in your own name and for your own account (or in the name and for the account of the legal person you may be acting for).
* The DAO and/or the Association may, at any time and in their absolute discretion, without prior notice and without reason:
* add, remove or modify (additional) requirements to access and use the Platform; or
* restrict or remove your access and use of the Platform,
in each case without you having any sort of remedy, claim, right or similar against the DAO and/or the Association.
## **3. Disclaimers**
You understand and agree to the following disclaimers:
* No control over assets or liquidity: The Platform works autonomously without the use of smart contracts. Neither the DAO nor the Association, at any point in time, have access to or in any way control of any assets in connection with your Wallet, of any of your liquidity positions (including any Rewards earned on such positions) in Partner Protocols and/or Vaults or in any other third-party protocols or else.
* Partner Protocols: Third-party Partner Protocols may integrate and use the Platform. You understand and acknowledge that neither the DAO nor the Association is soliciting, recommending, endorsing or intermediating between the Partner Protocols or in any other way responsible for any of your interactions with the Partner Protocols (in particular any liquidity positions you may have in such Partner Platforms). Your interaction with any Partner Protocol is entirely in your own name for your own account and at your own risk. Members of [Turtle](http://turtle.xyz) community may conduct (technical) due diligence on Partner Protocols before their integration and use of the Platform, which, however, is not intended to constitute any sort of recommendation or endorsement to use or interact with such Partner Protocols.
* No permanent relationship with you: Neither these Terms nor your actual access or use of the Platform is intended to create any sort of (permanent) (business) relationship between you and the DAO or the Association. There is no fee for accessing or using the Platform, and you do not rely on the DAO or the Association to provide you with any services.
* Distributed governance: Decisions regarding the Platform may be governed by a dispersed group of supporters, contributors, and participants through the technical governance rules of the Platform and TURTLE. You might participate in the governance process in accordance with such functionalities and parameters. You acknowledge and agree that governance decisions may not be in your favour or may have negative effects on you.
* TURTLE: The turtle token (the "**TURTLE**") may be implemented to provide certain utility and functionality in connection with the Platform, under technical, economical, legal and other limitations as may apply. TURTLE is not intended to (i) confer or represent any right of any form, including but not limited to any equity or ownership, voting, distribution, redemption, liquidation, intellectual property, participation, or any sort of right to receive future revenues, profit shares, or similar, (ii) create or confer any enforceable contractual or other legal obligations against any person or entity (including, but not limited to, the Association, any of the directors, team members, founders, developers, employees, auditors, other contractors, and similar persons associated with the Platform, [Turtle](http://turtle.xyz) project entirely or the Association), (iii) are not any kind of loan, investment, or other form of participation in the Association or the Platform or [Turtle](http://turtle.xyz) project entirely; and (iv) are not intended to be used as a means of payment or similar.
* No partnership: Members do not agree to and do not state their will to enter into or create a simple partnership, joint venture, or similar sort of legal or factual partnership by accessing or using the Platform, by obtaining, holding or using TURTLE, by participating in Platform governance and/or by interacting with the Platform in any other way.
* Informational content: The Platform as well as any communication published on other channels (e.g., discord, X, Telegram, etc.) provides informational content and documentation regarding the functionalities, use cases, community and developments of the Platform. You understand and acknowledge that any content, in particular any references to the Platform or accompanying documentation (e.g., the whitepaper) published is intended to be of a purely informational nature and entirely subject to change. In particular, none of the content is to be understood as any kind of professional or non-professional advice, including but not limited to financial, investment, legal, or tax advice. There is no warranty (express or implied) of completeness, actuality, accuracy, and suitability for any specific purpose of the content of the Platform.
There may be phishing attacks, impersonators and other malicious activities conducted by third parties, aiming to deceive you into connecting to fraudulent contracts, or otherwise exploiting you. You have sole responsibility to verify the authenticity and accuracy of any information related to [Turtle](http://turtle.xyz), to ensure you do not connect your Wallet to fraudulent contracts, to refrain from otherwise sending assets to a third party or granting access to assets to a third party, and all similar measures taken by you in connection with the access and use of the Platform. Neither the DAO nor the Association is liable to you for any losses or damages you may incur as a result of such activities.
* No fiduciary duties: Neither these Terms nor your access and use of the Platform are intended to create any fiduciary duties. To the fullest extent permissible under applicable law, you agree that neither your access or use of the Platform causes the DAO or the Association or any other person to owe fiduciary duties or liabilities to you or any third-party. Further, you acknowledge and agree to the fullest extent such duties or liabilities are afforded by applicable law, those duties and liabilities are hereby irrevocably disclaimed, waived, and eliminated, and that the DAO or the Association and any other third-party will be held completely harmless in relation thereof.
## **4. Assumption of risks**
The following list contains some of the risks associated with the use of the Platform, without being exhaustive:
* DEFI IS INHERENTLY RISKY AND HIGHLY EXPERIMENTAL. ANY ASSETS USED IN CONNECTION WITH THE PLATFORM, WITH PARTNER PROTOCOLS OR WITH DEFI IN GENERAL ARE AT RISK OF BEING LOST INDEFINITELY OR LOSING (ALL) THEIR VALUE, WITHOUT ANY KIND OF CONSIDERATION.
* The Platform integrates with other DeFi applications or services (including Partner Protocols) which may carry substantial risks. The intended functioning of the Platform may to some degree be dependent on the proper functioning of such other DeFi applications or services. You should conduct your own research on any such other DeFi applications or services before interacting with the Platform.
* Interacting with the Platform and/or Partner Protocols may carry substantial financial risks. Tokens (including TURTLE), and any transactions done with tokens, are by nature highly experimental, risky, complex and challenging to understand, and volatile. You understand, acknowledge, and agree that any interactions in connection with the Platform are unsolicited and solely initiated, and their outcome is solely borne, by you. The risk of loss in interactions with tokens in connection with the Platform may be substantial, up to a complete loss. You should, therefore, carefully consider whether this is suitable in light of your circumstances, financial background, and financial resources. You represent and warrant that you have been, are, and will be solely responsible for making your independent appraisal, investigations, and research into the risks of any given interaction and that you have sufficient knowledge, market sophistication, access and use of professional advice, and overall experience to make a thorough evaluation of the merits and risks involved. Nobody is responsible or liable for any financial loss or injury sustained from interacting with the Platform.
* The Platform could be impacted by one or more regulatory inquiries or regulatory actions, which could impede or limit the availability of the Platform and your continued use of the Platform. The Platform has not been reviewed, registered, approved, or licensed by any regulatory agency or authority.
* Further risks associated with the use of the Platform may include but are not limited to, risks of software weakness (of the underlying blockchain infrastructure or any Partner Protocol or any Platform or any other software), risks associated with uncertain laws and regulations, risk of abandonment, lack of success or business failure, speculation risk, risks associated with other applications, risks associated with markets for the cryptographic tokens, risk of losing access to cryptographic tokens due to loss of private key(s), custodial errors or errors of you, risks of hacking, theft and vulnerabilities, risks of mining or validation attacks, risks of incompatible wallet services, risks of hard forks, risk of uninsured losses, risks arising from taxation, risks of an unfavorable fluctuation of currency value, risk of dissolution of the network, risk arising from lack of legal rights, risk associated with third-parties, jurisdiction related risks and/or any unanticipated risks. Any and all of these risks could disrupt the underlying technologies and result in a total loss of cryptographic assets, their market value, or any digital funds. You are solely responsible for the safekeeping of the private key or other credentials associated with the blockchain address used to interact with the Platform. IF YOU ARE NOT COMFORTABLE ASSUMING ANY AND ALL RISKS RELATED TO THE ACCESS AND USE OF THE PLATFORM OR ENGAGING IN TRANSACTIONS THAT RELY ON SMART CONTRACTS, DIGITAL ASSETS AND CRYPTOGRAPHIC TOKENS, AND OTHER EXPERIMENTAL TECHNOLOGY, DO NOT USE THE PLATFORM.
## **5. Prohibited Use and Excluded Persons**
### **5.1 Prohibited Use**
You may not access or use the Platform for unlawful purposes or not in accordance with these Terms ("**Prohibited Use**"). You specifically agree to not use the Platform:
* In any way that violates, or could (assist in) violate (violating), any applicable domestic, foreign, or international law, statute, ordinance, or regulation, or any sanctions programs administered in any relevant country or in any way which would involve proceeds of any unlawful activity;
* to cause the Platform to work other than as intended;
* to take any action that may be reasonably construed as fraud, deceit, manipulation or any sort of other criminal behaviour; and
* to damage the reputation of the DAO/Association or the Platform.
Additionally, you agree not to:
* Circumnavigate, by any means, any restriction we may have implemented to prohibit impermissible access to Excluded Persons;
* be likely to deceive or defraud, or attempt to deceive or defraud, any person, including (without limitation) providing any false, inaccurate, or misleading information (whether directly through the Platform or through an external means such as through any frontend) with the intent to unlawfully obtain the property of another or to provide knowingly or recklessly false information, including in any way that causes inaccuracy among the role of the Association, the content on the Platform or on the functionalities of the Platform;
* give the wrong impression that any services, offerings, or functionalities other than the Platform as outlined in section 2 are offered, provided, or otherwise endorsed by the DAO/Association;
* promote any illegal activity, or advocate, promote, or assist any unlawful act;
* give the impression that they emanate from or are endorsed by the DAO/Association or any other person or entity if this is not the case;
* use the Platform in any manner or with the use of any tool, device, or software that could disable, overburden, damage, impair, or interfere with any other Member's use of the Platform;
* introduce any viruses, trojan horses, worms, logic bombs, or other material that is malicious or technologically harmful to the Platform, the Platform, the participants, any underlying blockchain, or any of the Platform's related utilities or functionalities;
* encourage or induce any third-party to engage in any of the activities prohibited under these Terms; and
* otherwise interfere with or attempt to interfere with the proper working of the Platform or the Platform in any way.
### **5.2 Excluded Persons**
You may not access or use the Platform if you are (each, either a natural person or as a legal entity, an "**Excluded Person**"):
1. a citizen of an Excluded Jurisdiction;
2. domiciled in, resident of, or physically present / located in an Excluded Jurisdiction;
3. not of legal age (in any case at least eighteen years old) and not fully capable of judgment and action;
4. incorporated in, or operate out of, an Excluded Jurisdiction;
5. under the control of one or more individuals who is/are citizen(s) of, domiciled in, residents of, or physically present / located in, an Excluded Jurisdiction; or
6. in any other way prohibited or ineligible in any way, in part or in full, under applicable laws to such person or entity, to access and/or use the Platform.
For purposes of these Terms, an "**Excluded Jurisdiction**" means any of the following jurisdictions:
* the United States of America;
* the United Kingdom;
* a country or territory (together "**Sanctioned Countries**") that is currently the subject of any sanctions or trade embargos administered or imposed by (1) Switzerland, (2) the United Nations Security Council, (3) the European Union or any member state of the European Union, (4) U.S. authorities, in particular OFAC and the U.S. Department of State, (5) your country of residence, or (6) by another authority having jurisdiction over your assets;
* a jurisdiction identified by the Financial Action Task Force ("**FATF**") for strategic AML/CFT deficiencies and included in FATF's listing High-Risk Jurisdictions; and
* a jurisdiction (including, but not limited to, the Sanctioned Countries) in which the actions contemplated under these Terms are prohibited, restricted, or unauthorized in any form or manner whether in full or in part under the laws, regulatory requirements, or rules in such jurisdiction.
## **6. Liability and indemnity**
TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW, THE DAO OR THE ASSOCIATION MAY NOT BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE, IN CONNECTION WITH THE USE OR INABILITY TO USE THE PLATFORM (INCLUDING BUT NOT LIMITED TO LOSS OF THE DIGITAL ASSETS OR TOKENS, ALLOCATION OR NON-ALLOCATION OF FEES, LOSS OF DATA, BUSINESS INTERRUPTION, DATA BEING RENDERED INACCURATE OR OTHER LOSSES SUSTAINED BY YOU OR THIRD-PARTIES RELATED TO THE SERVICES AND/OR ANY ACTIVITY RELATED TO ANY DAPP OR A FAILURE OF THE PLATFORM TO OPERATE WITH ANY OTHER SOFTWARE). The DAO/Association will not be held liable for the inaccuracy or incompleteness of the Platform, or the incompatibility of the Platform with any specific objectives that you are hoping to achieve.
You agree to indemnify and hold the Association harmless from and against any loss, damage, liability, claim, or demand, including reasonable attorneys' fees and expenses, made by any third party due to or arising out of (i) any breach of these Terms or any law or regulation by you, your affiliates, your employees or any other persons acting your behalf; (ii) any breach of your representations and warranties set forth in these Terms, or (iii) your violation of the rights of a third party.
You acknowledge and agree that upgrades and modifications to the Platform may be managed in a community-driven way. Neither the DAO itself, the Association or any developer, contributor, entity, any of its representatives or directors or any other persons involved in any way with the Platform are liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with Members of, the Platform, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or loss of profits, cryptocurrencies, tokens, or anything else of value.
## **7. No representations and warranties**
You expressly understand and agree that you use the Platform at your own risk. THE ASSOCIATION MAKES NO AND EXPRESSLY DISCLAIMS ALL REPRESENTATIONS AND WARRANTIES, EXPRESS, IMPLIED, OR STATUTORY, WITH RESPECT TO THE PLATFORM, WHETHER PROPRIETARY OR OPEN SOURCE. THE ASSOCIATION SPECIFICALLY DOES NOT REPRESENT AND WARRANT AND EXPRESSLY DISCLAIMS ANY REPRESENTATION OR WARRANTY, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING WITHOUT LIMITATION, ANY REPRESENTATIONS OR WARRANTIES OF TITLE, NONINFRINGEMENT, MERCHANTABILITY, USAGE, SECURITY, SUITABILITY, OR FITNESS FOR ANY PARTICULAR PURPOSE, OR AS TO THE ABSENCE OF ANY DEFECTS IN THE PLATFORM. THE ASSOCIATION DOES NOT REPRESENT OR WARRANT THAT THE PLATFORM AND ANY RELATED INFORMATION ARE ACCURATE, COMPLETE, RELIABLE, CURRENT, OR ERROR-FREE, AND THE PLATFORM IS PROVIDED STRICTLY 'AS IS' AND 'AS AVAILABLE'. THE ASSOCIATION FURTHER EXPRESSLY DISCLAIMS ALL REPRESENTATIONS AND WARRANTIES REGARDING ANY THIRD-PARTY TECHNOLOGY, INCLUDING ALL BLOCKCHAIN INFRASTRUCTURES AND DAPPS, WHICH MAY BE USED BY YOU IN CONNECTION WITH THE USE OF THE PLATFORM (E.G., THIRD-PARTY WALLET SOFTWARE).
THE ASSOCIATION FURTHERMORE DOES NOT REPRESENT AND WARRANT AND EXPRESSLY DISCLAIMS ANY REPRESENTATION OR WARRANTY, EXPRESS, IMPLIED, OR STATUTORY, THAT THE PLATFORM WILL REMAIN AVAILABLE IN ANY JURISDICTION WHERE IT IS CURRENTLY AVAILABLE AND DOES NOT REPRESENT AND WARRANT THAT THE ASSOCIATION CAN GUARANTEE THE LEGALITY OF THE PLATFORM IN ANY SPECIFIC JURISDICTION.
## **8. Intellectual Property**
All rights, titles, and interests to its own intellectual property, including all copyrights, inventions, trademarks, designs, domain names, know-how, trade secrets, data and other intangible property rights remain vested in the Association.
Notwithstanding the above, you understand and acknowledge that certain aspects or parts of the Platform may be published under an open-source license or may use, incorporate, contain or link to components under an open-source license. In such case, your use of the Platform is subject to, and you will comply, with any such applicable open-source license(s).
## **9. Miscellaneous**
**Entire Agreement**: These Terms, including any additional documents that are incorporated into these Terms by reference (if any), constitute the entire agreement relating to your use of the Platform. Your general terms and conditions are excluded.
**Changes to Terms**: The Association may, from time to time, change these Terms in its sole discretion and without any prior announcement. The Terms at the time of access or use of Platform apply.
**No Assignment**: You may not assign any of its rights, obligations, or claims under the Terms without the previous written and express consent of the Association.
**Severability**: If any provision of the Terms (in whole or part) is held to be illegal, invalid or otherwise unenforceable, the other provisions will remain in full force and effect.
**Governing Law & Jurisdiction**: These Terms, and all claims or causes of action that may be based upon, arise out of or relate to these Terms shall be governed by and construed in accordance with substantive Swiss law, excluding its conflict of law provisions and the United Nations Convention on Contracts for the International Sale of Goods (CISG). The ordinary courts at the seat of the Association have jurisdiction for all disputes arising from or in connection with the Terms.
**Class action and jury trial waiver**: You must bring any and all disputes against the Association in your individual capacity and not as a plaintiff in or member of any purported class action, collective action, private attorney general action, or other representative proceeding. This provision applies to class arbitration. You and the Association both agree to waive the right to demand a trial by jury.
## **10. Contact Information**
For any inquiries or concerns regarding these Terms and Conditions or the [Turtle](http://turtle.xyz) Protocol, please contact: [info@turtle.xyz](mailto:info@turtle.xyz)
# Defi Opportunities
Source: https://docs.turtle.xyz/liquidity-products/general-defi
Turtle offers access to opportunities across defi.
Turtle indexes opportunities across defi to give users the ability to deposit into various opportunities and optimize their portfolio. These opportunities are also accessible to Distribution Partners who might offer them in their own UI through the Earn API.
Turtle does not do diligence on all opportunities available in the Turtle Earn webapp or Earn API. The only opportunities with detailed Turtle diligence are [Liquidity Campaigns](/liquidity-products/turtle-deals).
## How Defi Opportunities Work
The Turtle team has built a sophisticated indexing system to track data and integrate deposit/withdraw flows with the largest defi protocols in the ecosystem.
Opportunities appear in the [Turtle Earn app](https://app.turtle.xyz) under the Discover section. Members deposit through the opportunity-specific page.
Emissions are sent to the user wallets as compounding value or to be claimed in the Earnings tab in the Opportunity page or Portfolio.
## For Protocols
Protocols use Opportunities to make judgements on incentive rates and provide access to their network via the Earn SDK or API.
Integrate thousands of defi opportunities or utilize Turtle's API to showcase a rich dataset of defi information and investment opportunities for your userbase.
# Liquidity Leaderboard
Source: https://docs.turtle.xyz/liquidity-products/leaderboard
Turtle's leaderboard rewards users for their activity across the network.
Turtle's liquidity leaderboard rewards users for depositing and referring liquidity through Turtle [Yield Opportunities](/liquidity-products/turtle-vaults). Boosts to your score also come from social activity, such as Cookie3 Snaps, Kaito Yaps, and connecting Telegram.
## Leaderboard Season 2
The current season uses **Turtle Shells** in place of the Distribution Score, and Shells are distributed continuously at the time of deposit. This season recycles the tokens forfeited in the Claiming Process to be distributed during the Liquidity Leaderboard.
**Rules for Turtle Shells:**
Turtle users **must** connect their Twitter to be included in the Leaderboard competition!
All rules for the leaderboard are subject to change as the season progresses. Liquidity must be deposited into eligible vaults in the Turtle frontend to count toward your score.
* **Deposited Liquidity:** 1 Shell per \$1 USD deposited
* **Referred Liquidity Boost:** 2 Shells per \$1 USD deposited
* **Social Boost (Kaito + Cookie)**
* Top 10: 2x
* Top 50: 1.5x
* Top 100: 1.25x
* **Telegram Connection:** 5%
* **Twitter Connection:** 5%
* **Airdrop Vesting Boost:** Airdrop recipients who vest their full airdrop will receive a reward at the end of the vesting period. ***Note: vesting tokens count toward your staking boost!***
* **Staking Boost:**
* if \$sTURTLE / (\$liquidity deposited + liquidity referred) = 1 then receive max boost (3x)
* Boost reduces linearly based on the staking ratio
* Unclaimed Turtle \$value = Staked Turtle \$value
Season 2 rewards have no defined distribution date. They may be distributed in "epochs" based on changes in the algorithm throughout the season.
## Leaderboard Season 1 (past season)
Season 1 is a prior season, kept here for reference. The current scoring rules are in the Season 2 section above.
The Season 1 rules prioritized referred and deposited liquidity, and then applied boosts based on a variety of social factors.
**Distribution Score:** A user's Deposit Score defined the leaderboard ranking.
**Liquidity Score:** The base score was the most important part of the ranking. It was calculated by summing the normalized value of liquidity referred and liquidity deposited by the user. *Referred Liquidity was also given a 10x boost* to the normalized value, making referred liquidity *far more important* than liquidity deposited by the user themself.
To qualify for referred liquidity, ensure your referees are using your referral link found in the leaderboard page.
**Boosts:** A user's base score was boosted by a variety of actions.
* Telegram Connection: 5%
* Twitter Connection: 5%
* Top 50 on Cookie3 or Kaito Leaderboard: 2x
* Top 10 on Cookie3 or Kaito Leaderboard: 3x
## Qualified Vaults
While Turtle offers many vaults in our frontend, only liquidity deposited via the frontend is tracked and counted toward users' liquidity score. You may get credit for Turtle boosts via outside interfaces. Vaults marked in green are qualified, while those marked in red do not qualify for the leaderboard.
## Rewards
Turtle allocates rewards to each leaderboard season. Every week a snapshot is taken and credit is distributed across leaderboard participants in Turtle's backend. At the end of the season the tokens allocated for rewards are distributed pro rata based on credits earned every week.
# Liquidity Campaigns
Source: https://docs.turtle.xyz/liquidity-products/turtle-deals
Turtle-structured liquidity campaigns that pay LPs extra rewards on top of a vault's base yield.
A Liquidity Campaign is an incentive arrangement that Turtle structures with a protocol. Within Campaigns are Deals, specific vaults or defi opportunities available for LPs to deposit into. Liquidity providers in Turtle Deals earn extra rewards on top of the native yield. The protocol commits a budget of token emissions to attract liquidity from Turtle's member network, Turtle sources that liquidity and tracks how much TVL each participant contributes over time, and the reward is paid out to LPs in proportion to what they contributed. Unlike a [Stream](/partner-products/streams/overview), which a protocol configures and runs itself, a Liquidity Campaign is relationship-sourced: Turtle structures the terms and brings the liquidity.
Every Liquidity Campaign, and subsequent Deals, goes through the Turtle Due Diligence Council before it goes live, a review that general DeFi opportunities in the Turtle Discover page do not receive. If you are an LP, a Liquidity Campaign is a vault that pays more than its native yield while you hold it. If you are a protocol, a Liquidity Campaign is how you buy targeted, attributed liquidity without building a distribution channel of your own.
Rewards or additional incentives are layered on top of a vault's native yield. **Turtle Network TVL** is the Turtle-attributed liquidity a fee is charged on, measured by reconciling who interacted with Turtle against their balance in the target opportunity. See the [glossary](/resources/glossary) and [Pricing](/resources/pricing).
## What you get
Deposit into a Turtle Deal through the [Turtle app](https://app.turtle.xyz) and earn extra token emissions on top of the vault's base yield. The additional incentive is automatic once you deposit into an eligible Deal. You keep custody of your position, and rewards accrue in proportion to the liquidity you contribute over the liquidity campaign period.
Turtle structures the terms, sources liquidity from its member network, and attributes the resulting TVL back to your protocol on a verifiable basis. You commit an emission budget and pay a fee on Turtle Network TVL. You do not build distribution infrastructure, and every dollar charged is tied to liquidity Turtle can prove it brought.
## How a liquidity campaign works
The Turtle team works with the protocol to set the emission token, reward rate, duration, and which vaults are eligible. The protocol's organization is reviewed and the liquidity campaign passes a diligence gate before anything goes live.
Once terms are signed, the liquidity campaign appears as a Turtle Deal in the [Turtle app](https://app.turtle.xyz). Eligible vaults are labeled so LPs can find them while browsing.
Members deposit into the eligible vault through the standard flow. The reward attaches automatically. Turtle tracks each wallet's contribution to the liquidity campaign's TVL from the go-live date forward.
Attribution reconciles who interacted with Turtle infrastructure against the balance those wallets hold in the target opportunity. This is what determines the Turtle Network TVL a fee is charged on, and the basis on which LP rewards are computed.
Rewards accrue to participating wallets in proportion to the liquidity they contributed during the liquidity campaign. LPs see and claim rewards in the app alongside their other Turtle activity.
## Liquidity Campaigns compared to Streams
Both products pay LPs for providing liquidity, and both attribute TVL on-chain. The difference is who runs the campaign.
| | Liquidity Campaign | Stream |
| ------------------------ | --------------------------------------------------------- | ------------------------------------------------------- |
| Who sets it up | Turtle structures and sources liquidity | The protocol configures it self-serve |
| Who brings the liquidity | Turtle's member network | The protocol's own audience, plus Turtle members |
| Commercial model | Fee on Turtle Network TVL | Creation fee plus the rewards you fund |
| Best for | A protocol that wants Turtle to drive a liquidity outcome | A protocol that wants to run its own incentive campaign |
If you want to run a campaign yourself rather than have Turtle source liquidity for you, see [Streams](/partner-products/streams/overview).
# Yield Opportunities
Source: https://docs.turtle.xyz/liquidity-products/turtle-vaults
Selected, diligence-reviewed DeFi vaults you deposit into to earn yield, with custody of your funds the whole time.
A Turtle vault is a DeFi yield opportunity that Turtle has reviewed and listed in one place so you do not have to hunt for it. You browse a catalog of vaults across many chains, deposit into the ones you want, and earn the underlying protocol's yield plus any rewards Turtle has layered on top. Your funds stay in your own wallet's control throughout: Turtle builds the transactions, you sign them.
If you are a liquidity provider who wants vetted places to put capital without researching every protocol yourself, the vault catalog gives you a reviewed shortlist and a single deposit flow.
A **vault** here is any listed yield opportunity (a lending market, a stablecoin strategy, a staking position). The **Turtle Due Diligence Council (TDC)** is the team that reviews each one before it appears in the catalog. See the [glossary](/resources/glossary).
## What you get
A reviewed catalog instead of a search problem. Filter by chain, token, APY, and TVL, deposit with the token you already hold, and earn base yield plus any active rewards. You keep custody the whole time.
Rewards stack. On top of a vault's native yield you can earn Liquidity Campaigns emissions, Streams rewards, and leaderboard points from the same deposit, with no extra steps.
## How a vault works
Turtle works with vault protocols (Morpho, Euler, Yearn, Mellow, and others) to list their opportunities. Each one passes a Turtle Due Diligence Council review before it appears in the catalog.
You explore the catalog in the [Turtle app](https://app.turtle.xyz), filter to what fits, and deposit. You can deposit with a token you already hold even when it is not the vault's native token, and the app handles the conversion.
The vault strategy manages the underlying position. You earn the protocol's base yield, plus any active [Liquidity Campaigns](/liquidity-products/turtle-deals) or [Streams](/partner-products/streams/overview) rewards tied to that vault.
You withdraw back to your wallet. Some vaults settle in one transaction; others queue the request and finalize a little later (see vault types below).
To build deposit and withdraw flows into your own app, see the [developer quickstart](/sdk/earn/quickstart).
## Vault types
Vaults differ in how a deposit settles. This matters because it changes what you do after you submit.
| Type | What happens | Example protocols |
| ----------- | ------------------------------------------------------------ | ----------------- |
| **Instant** | Your deposit settles in a single transaction. | Morpho, Yearn |
| **Async** | The vault queues your deposit and settles it a little later. | Mellow, Lagoon |
With an async deposit you come back and finish it from the app once it is ready. The [deposit guide](/products/vaults/deposit-and-withdraw) walks through both, including what to do when an async deposit is still pending.
If you are integrating against the API, check `depositStepsType` on any opportunity object to tell the two apart: `instant` or `complex`.
## What is in the catalog
Turtle lists a large catalog of opportunities across several kinds of yield:
* Lending vaults that supply assets to lending markets for interest
* Stablecoin vaults that earn on USDC, USDT, DAI, and others
* Staking vaults for liquid staking and restaking positions
* Strategy vaults that run multi-step strategies managed by curators
Opportunities span Ethereum, Base, Arbitrum, Avalanche, BSC, Optimism, Polygon, Linea, Scroll, Katana, and more, with chains added over time.
## Is it safe to deposit?
Every listed vault passes a Turtle Due Diligence Council review, and you keep custody of your funds the entire time. Turtle never holds your assets; it builds the transactions and your wallet signs them.
Audits, proof of solvency, the diligence process, and the self-custody model.
# Managing Liquidity Campaigns
Source: https://docs.turtle.xyz/partner-products/deals-dashboard
Monitor performance, adjust, and wind down a live liquidity campaign after launch.
Once a liquidity campaign is live, LPs deposit into the associated vaults and Turtle attributes the resulting TVL. From there you watch performance, adjust the liquidity campaign while it runs, and settle it at the end. This page covers the post-launch lifecycle from the [Liquidity Campaigns dashboard](https://dashboard.turtle.xyz), the protocol-facing section of the Client Portal. If you have not launched yet, start with [Launch a Liquidity Campaign](/products/deals/launch-a-deal); for what a liquidity campaign is, see the [Liquidity Campaigns overview](/liquidity-products/turtle-deals).
| Feature | Description |
| -------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| **Submit new deals** **(coming soon)** | Propose a new incentive deal for Turtle's member network. Turtle reviews and approves before launch. |
| **Manage active deals** | View deal status, emission schedules, and eligible deals. |
| **Track member activity** | See deposits, withdrawal activity, and unique wallet counts attributed to your deal. |
| **Monitor TVL impact** | Track how much Turtle-attributed TVL is deployed in your protocol over time. |
| **View deal history** | Access past deals with their final TVL figures and settlement data. |
Specify the integration details, deal diligence, emission token rate, and campaign duration.
The Turtle team reviews the proposal including diligence on the protocol and vault safety.
Once approved, the deal appears as an opportunity in the Turtle app. Members can start depositing.
Monitor real-time metrics in the dashboard (deposits, TVL, wallet counts) throughout the deal period.
Which of these actions you do in the Client Portal versus with the Turtle team is still being confirmed, so each section below flags what needs checking against the live product.
## Monitor performance
The Liquidity Campaigns dashboard shows how your live liquidity campaign is performing: Turtle member deposits, unique wallet counts, and the attributed TVL deployed in your protocol over time.
The figures here are scoped to the liquidity campaign and measured against Turtle Network TVL, the same basis fees are charged on. The headline numbers to watch:
* **Deposits and member activity:** deposits and withdrawals from Turtle members attributed to the liquidity campaign.
* **Unique wallets:** how many distinct wallets have contributed liquidity.
* **Attributed TVL:** the Turtle-attributed liquidity deployed in your protocol, tracked over the life of the liquidity campaign.
For how that attributed figure is computed and charged, see [Pricing](/resources/pricing). For the wallet-level deposit feed behind these numbers, the distributor-scoped activity endpoint is documented at [Distributor Activity](/sdk/earn-api/deposits).
## Adjust a live liquidity campaign
A live liquidity campaign's terms (incentive rate, duration, eligible vaults, emission budget) are set in the signed statement of work. Changing them is a commercial change, not a self-serve toggle, so adjustments go through the Turtle team rather than a Portal field.
## Re-review and flagging
A live liquidity campaign can be re-reviewed and re-flagged by the [Turtle Due Diligence Council](/resources/turtle-due-diligence-council) if something material changes, for example a new audit finding, a change to custody or control, or a counterparty or oracle change.
## Wind down a liquidity campaign
When a liquidity campaign reaches the end of its duration, it stops accruing new rewards and the incentive window closes. Attributed TVL is reconciled for the final period and the liquidity campaign settles against the terms in the SOW.
LPs keep their positions and anything they have already earned. Winding a liquidity campaign down ends the additional rewards going forward, it does not remove liquidity or take back rewards already attributed. Opportunities available in a campaign will persist on Turtle in the general Discover page.
## How LPs see and claim rewards
LPs see the rewards they have earned in the [Turtle app](https://app.turtle.xyz) alongside their other Turtle activity, and claim there. You do not distribute rewards to LPs yourself; attribution and payout are handled through Turtle.
# Distribution Dashboard
Source: https://docs.turtle.xyz/partner-products/distribution-dashboard
What each panel of the distributor dashboard shows: deposits, attributed TVL, and revenue.
The Distribution Dashboard is the distributor-facing section of the [Client Portal](https://dashboard.turtle.xyz). It is where a distribution partner reads how their integration is performing: who deposited, how much TVL is attributed to them, and what revenue that has earned. If you arrived here from a stream, this is also where you watch a live campaign's participation and accrued rewards. This page is a screen reference for what each panel reports and where the underlying data comes from.
## Panels
| Panel | What it shows |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
| **Deposits** | Deposit activity attributed to your distributor: recent deposits, unique depositors, and volume over time. |
| **Attributed TVL** | The liquidity currently attributed to your integration, tracked over the life of your distribution. |
| **Revenue** | Earnings from the yield generated by the liquidity you route into Turtle vaults, against your configured revenue share. |
| **Distributor ID** | Your `distributor_id`, the identifier that scopes all of the above to your integration and that you pass when integrating the API. |
| **Streams** | For partners running incentive campaigns, participation and accrued rewards for your live streams. |
## Deposits
The deposits panel reads the activity attributed to your `distributor_id`: recent deposits, the count of unique depositors, and volume over time. It is the visual read on the same data the API exposes for programmatic use.
For the wallet-level feed behind this panel (every attributed deposit with its amount, token, chain, and transaction hash), see [Distributor Activity](/sdk/earn-api/deposits).
## Attributed TVL
This panel tracks the liquidity attributed to your integration over time. Attribution ties a deposit to your distributor through the `distributor_id` carried in the on-chain calldata, which Turtle detects automatically. To confirm that a specific deposit was attributed to you, see [Verify attribution](/sdk/earn/verify-attribution).
## Revenue
Distribution partners earn a share of the yield generated by the liquidity they route into Turtle vaults. The revenue panel reports earnings against your configured rate.
Revenue share rates are configured per distributor and are not published in the docs. You read your own rate and earnings in this panel.
## Streams orientation
If you run [Streams](/partner-products/streams/overview) campaigns, this dashboard is where you monitor them after launch: participant counts, recent snapshots, and accrued rewards across the life of each stream. The lifecycle actions (top up, pause, end early) are covered in [Managing a Stream](/partner-products/streams/campaign-management), and the per-wallet data behind the dashboard is at [Get Wallets](/sdk/streams/get-wallets).
# Become a Distributor
Source: https://docs.turtle.xyz/partner-products/distribution/become-a-distributor
How to onboard as a Turtle distributor: what you distribute, how you get paid, and the five steps from account to credentials.
A distributor shares Turtle deals with their audience and earns on the deposits it brings in. Each distributor has a unique `distributorId` that scopes endpoint responses to that integration and tags the deposits it generates. This page walks the full onboarding path: how distribution works, how you get paid, and the five setup steps.
Cohort 1 of the Turtle Distributor Program is open now. Apply through the [program page](https://creatorwire.xyz/turtle/), and see the [launch announcement on X](https://x.com/turtledotxyz/status/2078067577402675278).
## How you distribute
Once onboarded, you pick the deals you want to push from the Distribution tab of the [Client Portal](https://dashboard.turtle.xyz). There are two ways to put them in front of your audience:
* **[Share links](/partner-products/share-links)** - append your `distributorId` to any opportunity URL. No code required.
* **[API integration](/sdk/earn/quickstart)** - embed discovery and deposits natively in your product with the Earn API.
Either way, every deposit carries your `distributorId` onchain and is attributed to you automatically. There is nothing to report and no endpoint to call. See [how attribution works](/sdk/concepts/distributor-model) for the mechanics.
## How you get paid
Each deal lists a payout rate in the dashboard. Your earnings accrue against the TVL attributed to your `distributorId`, and payouts release automatically from the deal's escrow wallet, powered by [Turtle Streams](/partner-products/streams/overview). Payouts are based on verified onchain TVL: you are paid for liquidity that landed, with no invoicing on your side.
Deals with a funded escrow wallet are the ones Turtle features first, because their payouts can release the same day the TVL is verified. You can see your accrued earnings, attributed TVL, and deposit activity at any time in the [Distribution Dashboard](/partner-products/distribution-dashboard).
## The five steps
The full process runs inside the [Client Portal](https://dashboard.turtle.xyz), from profile to credentials.
Head to [dashboard.turtle.xyz](https://dashboard.turtle.xyz) to create an account and fill out your profile information.
Select "Create Organization" to begin setting up your entity.
Choose between "Individual" or "Legal Entity" depending on who is filing, complete the requested details, and sign the MSA.
Notify a member of the Turtle team to approve your account for distribution tooling. Once approved, your `distributorId` appears in the Distribution tab.
Under the settings menu, select "Create API Key" to generate your access credentials. You only need this for an API integration; share links work without one.
Distribution access is currently opening in cohorts, starting with the [Turtle Distributor Program](https://creatorwire.xyz/turtle/). If you have requested access and not heard back, reach out to your Turtle contact or on [Discord](https://discord.turtle.xyz).
## Your credentials
At the end of onboarding you hold the two credentials that matter:
* **`distributorId`** - your unique identifier. It scopes endpoint responses to your integration and tags every deposit you generate, so attribution and payouts map back to you.
* **API key** - your access credential for the Turtle API, generated from the dashboard once your profile is approved for distribution.
## Start distributing
With both in hand, pick your first deal in the Distribution tab and share it. For the no-code path, start with [Share links](/partner-products/share-links). To embed deposits in your product, follow the [Earn API quickstart](/sdk/earn/quickstart). To confirm a deposit was attributed to you, see [Verify attribution](/sdk/earn/verify-attribution).
# Distribute Your Deal
Source: https://docs.turtle.xyz/partner-products/distribution/distribute-your-deal
Put your deal in front of Turtle's distributor network, and why a funded escrow wallet gets it pushed first.
Turtle's distributor network puts your deal in front of audiences you do not reach directly: wallets, platforms, and operators vetted for the onchain liquidity they bring, not the impressions they generate. Distributors embed or share your deal, deposits land in your vault with onchain attribution, and payouts to distributors run automatically on Turtle's infrastructure. This page explains the flow and what it takes to get your deal into the program.
Cohort 1 of the Turtle Distributor Program is live: see the [program page](https://creatorwire.xyz/turtle/) distributors are onboarding through, and the [launch announcement on X](https://x.com/turtledotxyz/status/2078067577402675278).
## How it works
Distributors browse available deals in the Distribution tab of the [Client Portal](https://dashboard.turtle.xyz) and choose which ones to push.
Each distributor shares or embeds your deal through their own channels. Every deposit carries the distributor's ID onchain, so attribution is automatic and verifiable.
Distributors earn a payout rate on the TVL they bring to your deal. Payouts release automatically from your escrow wallet, powered by [Turtle Streams](/partner-products/streams/overview), against verified onchain TVL.
## Why fund your escrow wallet
Escrow funding is what moves your deal to the front of the queue.
**Funded deals get pushed first.** Deals with a topped-up escrow wallet are the primary deals Turtle surfaces to distributors, because distributors on those deals can be paid the same day their TVL is verified. Distributors see which deals have automatic payouts enabled, and they push those first.
**Your risk is zero.** Funds sit in escrow; they are never held by a distributor. Payouts release only against deposits that are attributed onchain and verified as TVL in your deal. You pay for liquidity that actually landed, nothing else.
**No operational overhead.** Streams handles the payout mechanics: accrual, verification, and release. There is no invoicing back and forth between you and the distributors pushing your deal.
## Get your deal in the program
If your deal is not live yet, start with [Launch a Deal](/products/deals/launch-a-deal).
The payout rate distributors earn on your deal is set with the Turtle team and surfaced to distributors in the dashboard.
Top up the escrow wallet for your deal. Your Turtle contact will walk you through it in the Client Portal.
Your deal is surfaced to the distributor cohort with priority placement for as long as the escrow stays funded.
To understand the other side of the marketplace, see [Become a Distributor](/partner-products/distribution/become-a-distributor). To watch attributed deposits and TVL on your deal, see the [Distribution Dashboard](/partner-products/distribution-dashboard).
# Distribution
Source: https://docs.turtle.xyz/partner-products/distribution/overview
Distribute Turtle deals to your audience and earn on every deposit you bring in.
Distribution is Turtle's partner product for anyone with an audience. You put vetted deals in front of your users, the deposits they make are attributed to you onchain, and you earn on the liquidity you route in. Attribution is automatic: every deposit carries your distributor ID, so you do not build tracking infrastructure or reconcile anything by hand.
If you have an audience that wants DeFi yield, a newsletter, a wallet, a mobile app, or a community, distribution lets you offer vetted opportunities and get paid for the deposits without running the vaults yourself. Cohort 1 of the Turtle Distributor Program is open now; onboarding starts at [Become a Distributor](/partner-products/distribution/become-a-distributor).
A **distributor** is the integration point that deposits are attributed to. Your **distributor ID** is the identifier that ties a deposit back to you. An **opportunity** is a vault or campaign a user can deposit into. See the [glossary](/resources/glossary).
New to the model? The [Distributor Model](/sdk/concepts/distributor-model) concept page walks through how attribution, opportunity scoping, and revenue share work, with a short video walkthrough.
## What you get
* **You** surface selected DeFi opportunities through a no-code link or a full API integration. Every attributed deposit earns a payout, tracked automatically against your distributor ID. No vault operation, no manual reconciliation.
* **Your users** deposit into vetted opportunities through an experience you control, in your product or through your link. They keep custody of their position and can withdraw on the vault's terms.
## How distribution works
Set up an organization, get a distributor ID, and pick an integration path: no-code share links or the Earn API. [Become a Distributor](/partner-products/distribution/become-a-distributor) walks the steps; [Before you start](/products/earn/before-you-start) is the preflight check.
Choose which opportunities from the Turtle catalog to put in front of your users, tailored to your audience. See [Configure opportunities](/products/earn/configure-opportunities).
Your users deposit through your link or your app. The deposit carries your distributor ID in its on-chain calldata.
Turtle detects the deposit on-chain and attributes it to your distributor automatically. No callback or reporting call is needed.
Earnings accrue against your attributed TVL and release automatically from the deal's escrow wallet. Attributed volume and earnings show up in the [Distribution Dashboard](/partner-products/distribution-dashboard).
## Two ways to integrate
There are two integration paths. Pick by how much control you want over the deposit experience and how much you want to build.
| Path | What you build | Best for |
| ----------- | ------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| Share links | Nothing. You share a per-opportunity link with your distributor ID attached. | KOLs, newsletters, content creators, and non-technical partners who want to start today. |
| Earn API | A custom deposit flow in your own product, generating and submitting transactions yourself. | Wallets, apps, and platforms that want deposits to happen inside their own interface. |
Share links work only with Turtle featured deals. The Earn API covers the full catalog. See [Configure opportunities](/products/earn/configure-opportunities) for how the two paths differ in what you can put in front of users.
## How you get paid
Each deal lists a payout rate in the dashboard. Your earnings accrue against the TVL attributed to your distributor ID and release automatically from the deal's escrow wallet, powered by [Turtle Streams](/partner-products/streams/overview). Deals with a funded escrow wallet can pay out the same day their TVL is verified, and those are the deals Turtle features first. Rates are set per distributor as part of your agreement with Turtle; attributed volume and earnings are visible in the [Distribution Dashboard](/partner-products/distribution-dashboard).
## What powers it
Distribution runs on the Turtle API, so you never build the mechanics yourself:
* **[Earn API](/sdk/earn/quickstart)** - the opportunity catalog, deposit and withdrawal transaction generation, and onchain attribution.
* **[Streams](/partner-products/streams/overview)** - the payout rails: distributor earnings release from deal escrow wallets as streams.
See the [API overview](/sdk/overview) for the full surface.
## Supported chains
Distribution opportunities span a broad set of chains, including Ethereum, Base, Arbitrum, Avalanche, BSC, Optimism, Polygon, Linea, and Scroll, with more added regularly.
## Get started
* [**Become a Distributor**](/partner-products/distribution/become-a-distributor) - The onboarding path, from account to credentials.
* [**Before you start**](/products/earn/before-you-start) - Org setup, your API key, your distributor ID, and choosing an integration path.
* [**Configure opportunities**](/products/earn/configure-opportunities) - Pick which opportunities to put in front of your users and keep them current.
* [**Share links**](/partner-products/share-links) - The no-code path: share a featured deal with attribution built in.
* [**Distribute your deal**](/partner-products/distribution/distribute-your-deal) - For deal owners: get the distributor network pushing your deal.
# Client Portal
Source: https://docs.turtle.xyz/partner-products/overview-partners
Set up your organization in the Turtle Client Portal, then route to the product that fits what you are here to do.
The [Client Portal](https://dashboard.turtle.xyz) at dashboard.turtle.xyz is where every Turtle partner sets up their organization, manages their team, and reaches the tools for the product they use. One org, one login, then a fork: protocols that want to attract liquidity go one way, distributors that want to earn revenue by surfacing Turtle opportunities go the other.
This page covers the portal-wide setup that everyone does, then points you to the right product. It does not re-explain those products; the links below go to their own overviews.
## Set up your organization
Sign up at [dashboard.turtle.xyz](https://dashboard.turtle.xyz/sign-in) with your email and wallet, then create your organization with your team, roles, and workspace.
A master services agreement (MSA) is signed during org setup. It is required before most product actions, including creating a stream or launching a liquidity campaign.
Creating an org starts a know-your-business (KYB) check and an integration fee invoice. The Turtle team approves new organizations before granting access to dashboards and API keys.
Invite teammates and assign roles for your organization. Team and role management is portal-wide and applies across whichever product you use.
## Choose your path
What you do next depends on why you are here.
You run a protocol or vault and want to bring in liquidity. If you want Turtle to structure terms and source liquidity for you, start with [Liquidity Campaigns](/liquidity-products/turtle-deals). If you want to run your own self-serve incentive campaign, start with [Streams](/partner-products/streams/overview).
You have an audience and want to earn revenue by surfacing Turtle vault opportunities to them. Start with [Distribution](/partner-products/distribution/overview) for the no-code and API integration paths.
For protocols running their own campaigns instead of a Turtle-sourced liquidity campaign, the self-serve path is [Streams](/partner-products/streams/overview).
# Share Links
Source: https://docs.turtle.xyz/partner-products/share-links
Share Turtle featured deals with automatic deposit attribution. No code required.
Share a link to a Turtle featured deal with your distributor ID attached. When someone deposits through your link, the deposit is attributed to you and counts toward your revenue share.
Share links are for distributors and partners who want a revenue share without writing any code: post the link, and any deposit made through it is credited to you.
Share links only work with **Turtle featured deals**, the opportunities listed on [app.turtle.xyz/earn/opportunities](https://app.turtle.xyz/earn/opportunities). Non-featured or external vault URLs will not trigger attribution.
## Link format
```
https://app.turtle.xyz/earn/opportunities/{slug}?distId={your_distributor_id}
```
| Part | What it is | Where to find it |
| -------- | ------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `slug` | The deal's URL identifier | Copy it from the URL bar when viewing the deal on [app.turtle.xyz](https://app.turtle.xyz/earn/opportunities) |
| `distId` | Your distributor ID | In the [Distribution Dashboard](https://dashboard.turtle.xyz) |
## Example
The Lido stETH deal is a featured deal on Turtle. Its slug is `lido-earneth`.
To share it with your distributor ID:
```
https://app.turtle.xyz/earn/opportunities/lido-earneth?distId=Y2Zi7KWy
```
The user lands on the Lido stETH deposit page. If they deposit, the deposit is attributed to `Y2Zi7KWy`.
## How it works
1. User clicks your link
2. The app reads the `distId` parameter and embeds your distributor ID into the deposit transaction
3. Turtle detects the deposit on-chain and attributes it to your account
No API integration or code needed. Attribution is automatic.
## Verify a deposit
The Earn API can confirm a deposit was attributed to you and returns the attributed distributor ID for a given transaction. Use it when you need to check attribution programmatically rather than in the dashboard.
See [Verify attribution](/sdk/earn/verify-attribution) for the request and response details.
## Sharing tips
Lead with the yield and the asset. Two lines plus the link is enough.
Earn stETH yield through Lido on Ethereum. One of the most battle-tested staking protocols in DeFi.
[https://app.turtle.xyz/earn/opportunities/lido-earneth?distId=Y2Zi7KWy](https://app.turtle.xyz/earn/opportunities/lido-earneth?distId=Y2Zi7KWy)
## Track deposits
View attributed deposits in the [Distribution Dashboard](https://dashboard.turtle.xyz), or query them programmatically through the Earn API to pull the deposits credited to your distributor ID into your own systems.
See [Distributor Activity](/sdk/earn-api/deposits) for the request and the full response format.
## Using the Earn API instead
Share links are the no-code path. If you want to build a custom deposit flow in your own app, use the [Earn API](/sdk/earn/quickstart). The same attribution applies.
# Before You Start
Source: https://docs.turtle.xyz/partner-products/streams/before-you-start
Prerequisites and the decisions to make before you launch your first stream.
A stream goes live in minutes once the groundwork is in place. This page is a preflight check. Run through it before you open the Client Portal so you are not stopped mid-flow by a missing permission, an unfunded wallet, or a token that is not allowlisted on your chain. If you already know what Streams is, skip ahead to [Choosing a reward model](/partner-products/streams/choosing-a-reward-model). If you are new, start with the [Streams overview](/partner-products/streams/overview).
## Prerequisites
Your organization must be set up and approved in the [Client Portal](https://dashboard.turtle.xyz). A master services agreement (MSA) and org setup are required even if you only plan to run streams. See [Client Portal setup](/partner-products/overview-partners).
Stream creation is gated by a `streams-create` permission on your organization. If your org does not have it yet, contact the Turtle team to turn it on.
If you do not see stream creation in the Client Portal, your org likely does not have `streams-create` enabled. Reach out to the Turtle team before you go further. The prerequisites are also listed in the [create-stream reference](/sdk/streams/create-stream).
For a token stream, the wallet that creates the stream must sit on the right chain and already hold enough of the reward token to cover the total reward amount plus the creation fee. Point streams have no on-chain step and no funding requirement at creation.
The creation fee is **1.5% of the funded reward amount** by default, charged in the reward token and pulled by the `StreamFactory` alongside the net total. Turtle Pro organizations are exempt from the fee (0%). The exact fee amount for your stream is returned as `FeeAmount` in the [create-stream](/sdk/streams/create-stream) response, and the Client Portal review screen also shows it. Point streams have no creation fee.
The reward token must be an allowed reward token. Confirm it is allowlisted on your chain before you commit to a launch. Resolve which tokens are allowed through [get-tokens](/sdk/streams/get-tokens).
Creating a token stream is currently supported on Ethereum, Base, Avalanche, BSC, and Sepolia (testnet). Target tokens, the tokens whose balances are tracked to measure TVL, span a broader set of chains. See [Supported chains](#supported-chains) below.
## Decisions to make before you launch
Have answers to these ready. Each one maps to a field you will set when you create the stream.
A stream pays either a real ERC-20 reward token or off-chain points, never both. Token streams settle on-chain. Point streams are created instantly with no on-chain step and can convert to tokens at a future TGE. Points support the mechanics that need no token price: Fixed Rate, Daily Budget, and Airdrop.
Best for tokens: you have a live, allowlisted ERC-20 and want LPs to claim it on-chain now. Best for points: you are pre-TGE or want to track contribution before committing real tokens.
See [Choosing a reward model](/partner-products/streams/choosing-a-reward-model) for the tradeoff, and [create-point](/sdk/streams/create-point) for the points path.
Decide what you pay for: **TVL-Based** (holders earn continuously against their balance), **Deposit-Based** (reward how long depositors commit, through duration tiers that unlock at cliffs), or **Airdrop** (a one-time distribution defined by a recipient list). Then pick the rate mechanic: Fixed APR, Fixed Rate, or Daily Budget as standard rewards, or a gap-fill rate (Target APR, Reference APR) that pays only when native yield falls short.
[Choosing a reward model](/partner-products/streams/choosing-a-reward-model) walks through each and when to use it.
Decide your budget and how long the stream runs. Streams are required to distribute a minimum of **\$33.33 per day**, which caps the maximum duration at your budget divided by that floor — the end date fills in from your budget automatically, and you can shorten it but not extend it past what the budget covers. Two API gotchas to plan around: start and end timestamps must align to 15-minute boundaries in UTC, and an end time must be at least one hour after the start. Rewards begin accruing after creation, and the first snapshot lands within about 12 hours. Exact formatting rules are in the [create-stream reference](/sdk/streams/create-stream).
Each mechanic takes one headline number. Fixed Rate takes a `tokensPerUSD` (reward tokens per 1,000 USD of TVL per day). Fixed APR takes an `apr`. Daily Budget takes a `tokensPerDay` and computes the total automatically, so you do not specify a total for this type. Target APR takes a `targetApy` (the floor to gap-fill to); Reference APR tracks another vault's rate with an optional `apyOffset` (both run under the API's `Yield Match` type). Deposit-based streams take a rate per duration tier. Airdrop takes no rate; you upload allocations yourself.
Name your number now. The exact format and base-units rules live in the [create-stream reference](/sdk/streams/create-stream).
Optionally, shape who earns and how much: scope eligibility by deposit route (All Deposits, Turtle Only, or Select Distributors), restrict to a whitelist or exclude a blacklist (OFAC screening is on by default), add percentage bonuses for linked X or Telegram accounts, referrals, or holders of a chosen asset, and forward vault rewards to underlying LPs. In the API these are configured at creation through the `adapters` array. See the [create-stream reference](/sdk/streams/create-stream) for the full list and configuration.
## Supported chains
Streams are live on the chains below. Reward-token creation is limited to this set. Target tokens are supported on a broader range of chains; resolve which tokens are available on a chain through [get-tokens](/sdk/streams/get-tokens).
| Chain | Status |
| --------- | ------- |
| Ethereum | Live |
| BSC | Live |
| Avalanche | Live |
| Base | Live |
| Sepolia | Testnet |
New chains are added by deploying a StreamFactory and configuring an indexer webhook. If the chain you need is not listed, see the contact path below.
## If your token is not allowlisted or your chain is not supported
Reward tokens must be allowlisted, and token-stream creation is currently limited to Ethereum, Base, Avalanche, BSC, and Sepolia. If your token is not yet allowed or your chain is not supported, reach out to the Turtle team through the [Client Portal](https://dashboard.turtle.xyz). The team can allowlist a token or scope a new chain deployment.
# Managing a Stream
Source: https://docs.turtle.xyz/partner-products/streams/campaign-management
Monitor, adjust, and wind down a live stream from the Client Portal and API.
Once a stream is live, rewards begin accruing and LPs can claim. From there you can watch participation, add funds, change the pace, or close the campaign out. This page covers the post-launch lifecycle and points to the dashboard and endpoints for each action.
Which of these actions you do in the [Client Portal](https://dashboard.turtle.xyz) versus the API is being confirmed, so each section below flags what still needs checking against the live product.
## Monitor performance
Track a live stream from two places: the Distribution Dashboard for a visual read on participation and accrued rewards, and the wallets endpoint for the underlying per-wallet data.
The Streams overview shows every stream with its incentive APR, cost per \$1k of TVL per day, distributed and remaining balance, projected spend, and a health score, alongside portfolio-level figures: qualified TVL, average incentive APR, LPs incentivised, and estimated monthly burn. The Distribution Dashboard adds participants, recent snapshots, and accrued rewards over the life of the stream. See [Distribution Dashboard](/partner-products/distribution-dashboard) for the full view.
For programmatic monitoring, `GET /v1/streams/{id}/wallets` returns each participating wallet, its TVL contribution, and its accrued reward balance. See [Get Wallets](/sdk/streams/get-wallets).
The reward updater runs about twice per day, so accrued figures reflect the most recent snapshot rather than the current second. A new stream's first snapshot lands within about 12 hours of creation.
## Top up or extend
A stream's total amount and duration are fixed at creation: streams are fully collateralized upfront, and the budget cannot be increased or decreased after launch. If you want the campaign to keep paying past what the original budget covers, plan the budget accordingly at creation — the end date is bounded by budget from the start (see [Create a Stream](/partner-products/streams/create-a-stream)) — or launch a follow-on stream when the first one ends.
Adding and withdrawing funds on a live stream is in development. Until it ships, treat the budget as immutable.
Withdrawing from a live stream follows the same rule in reverse: funds can be recovered only once the campaign has ended (the leftover), or for any amount above what the stream needs to stay fully collateralized.
## Pause or resume
Pausing halts reward accrual. While a stream is paused, no new rewards are computed for the time it sits paused, so that window does not count toward any wallet's balance. Resuming starts accrual again from the resume point.
Pausing does not touch rewards that already accrued. Anything committed on-chain before the pause stays claimable, and LPs can still claim during a pause.
## End a stream early
Ending a stream early stops accrual immediately. No further snapshots add to wallet balances after the end point.
LPs keep access to rewards that were already committed on-chain. Ending early closes the campaign without taking anything away from depositors who earned during the active window. They can claim before or after you end it.
## Recover unclaimed funds
After a stream ends, any reward tokens that LPs never claimed can be recovered by an authorized role. This returns leftover funds rather than leaving them stranded in the Stream contract.
Recovery is for funds left over after the campaign is over. It does not claw back rewards LPs are still entitled to claim. Confirm the campaign has genuinely ended before recovering.
## How LPs claim
LPs claim on their own schedule. The backend commits a Merkle root of the latest snapshot on-chain (roughly every 12 hours), and a wallet submits a Merkle proof to receive its rewards. Claims are cumulative, so a single claim transaction always pays the full outstanding balance. For TVL-based streams, each commit makes newly accrued rewards claimable; for deposit-based streams, rewards become claimable at each cliff.
Because claims are cumulative, an LP never has to claim on a schedule to keep up. One claim at any time pays everything committed so far.
Where that claim happens is up to you: on Turtle's app, embedded on your own front end, or claimed automatically on the LP's behalf. [Claiming rewards](/partner-products/streams/claiming-rewards) compares the three paths. For the underlying proof endpoint and contract calls, see [Get Merkle Proofs](/sdk/streams/get-merkle-proofs) and [Claim Rewards](/sdk/streams/claim-rewards).
# Choosing a Reward Model
Source: https://docs.turtle.xyz/partner-products/streams/choosing-a-reward-model
Pick the reward type and rate mechanic that fit your incentive goal, with plain examples for each.
Every stream runs on the same infrastructure: an indexer tracks the target token balance of every wallet, a reward updater computes accrued rewards about twice a day, and a Merkle root is committed on-chain so LPs can claim. What changes between streams is **what you pay for** (the reward type) and **how the rate is set** (the mechanic). Pick by your goal, not by the math.
## Quick chooser
| Your goal | Pick |
| ---------------------------------------------------- | ------------------------------ |
| Predictable cost per unit of TVL | TVL-Based · Fixed Rate |
| Advertise a headline APR | TVL-Based · Fixed APR |
| Fixed spend per day regardless of TVL | TVL-Based · Daily Budget |
| Guarantee depositors a minimum total yield | TVL-Based · Target APR |
| Match a competing vault's yield | TVL-Based · Reference APR |
| Sticky liquidity — reward how long depositors commit | Deposit-Based (duration tiers) |
| Manual or retroactive distribution | Airdrop |
Every model can pay either a token or points (points support the mechanics that need no token price — Fixed Rate, Daily Budget, and Airdrop), and every model tracks a target token whose balance measures each wallet's contribution. The reward source and the target token are independent of the model you pick. See [Before you start](/partner-products/streams/before-you-start) and the [glossary](/resources/glossary) for the terms used here.
## TVL-based streams
TVL-based streams pay by token value held — holders earn continuously against their balance, and each Merkle commit makes newly accrued rewards claimable. Choose one of the mechanics below.
### Fixed Rate
You set a flat number of reward tokens per 1,000 USD of TVL per day. Each wallet earns in direct proportion to how much it holds, and your total emission rises and falls with the pool TVL. Cost per unit of TVL stays constant no matter how large the pool gets.
**Best for:** a predictable, fixed cost for each dollar of liquidity you attract.
**Example:** you pay 2 reward tokens per 1,000 USD per day. A wallet holding 50,000 USD of the target token earns 100 tokens a day. If the pool grows, your daily spend grows with it, but the rate each LP sees never changes.
Decision parameter: `tokensPerUSD`. See [Create a stream (API)](/sdk/streams/create-stream) for the exact format and base-units rules.
### Fixed APR
You set an annualized percentage rate, for example 10 percent APR, paid on top of the native rate. At each snapshot, Turtle converts that APR into a per-day token figure using current prices, so the headline rate holds even as the token price moves. This is the model to use when you want LPs to see a clean APR number.
**Best for:** advertising a headline APR in your marketing and on listings.
**Example:** you set 10 percent APR. A wallet holding 50,000 USD of TVL earns roughly 5,000 USD worth of reward tokens over a year, paid out continuously as the stream runs. The token amount per day shifts with price so the percentage stays at 10.
Decision parameter: `apr`. See [Create a stream (API)](/sdk/streams/create-stream) for the exact format.
### Daily Budget
You fix a daily token budget and it is split pro-rata across all participating LPs. The pool total stays flat, so per-user rewards fall as more TVL joins and rise if TVL leaves — the APR it implies moves with TVL. Your spend is capped per day regardless of how much liquidity shows up.
**Best for:** a fixed daily spend where you want to cap total cost, not cost per LP.
**Example:** you budget 1,000 tokens a day. With 10 LPs holding equal amounts, each earns 100 tokens a day. If 10 more equal LPs join, the same 1,000 tokens now split 20 ways, so each earns 50.
The total emission is computed automatically from the daily budget times the duration, so you do not specify a total amount for this type.
Decision parameter: `tokensPerDay`. See [Create a stream (API)](/sdk/streams/create-stream) for the exact format.
### Target APR
A gap-fill rate. You set a target APR, and the stream pays only the difference between the target and the vault's native APY, measured against a trailing average over a lookback window you choose: **7 days, 1 month, 3 months, or 6 months**. The window changes the calculation, not just the chart — a longer lookback smooths the native APY the gap is measured against. If the vault yields 4 percent and your target is 4.75 percent, the stream pays the gap. If the vault already meets or exceeds the target, the stream pays nothing — the boost is never negative, and you never overpay when the vault is already performing.
**Best for:** guaranteeing depositors a minimum total yield without overpaying.
Target APR measures the gap against the target token's own native yield, so it is only offered for targets that have one. If your target has no native yield, a gap against zero is just a flat rate — use Fixed APR instead.
Decision parameters: `targetApy`, plus the lookback window (7 days / 1 month / 3 months / 6 months) for the trailing native-APY average. See [Create a stream (API)](/sdk/streams/create-stream) for each. In the API this runs under the `Yield Match` type with `targetApy` set.
### Reference APR
The second gap-fill rate. Instead of a fixed target, the stream tracks **another vault's rate** plus an optional offset, and pays only the shortfall between that reference and your vault's native yield.
**Best for:** matching or beating a competing vault's yield without overpaying when your own vault keeps up.
Decision parameters: in the API this runs under the `Yield Match` type with `targetApy` unset — set the reference vault and an optional `apyOffset`. See [Create a stream (API)](/sdk/streams/create-stream).
For gap-fill streams, the configuration is locked at creation and cannot be changed later, so decide the target or reference before you create the stream.
## Deposit-based streams
Deposit-based streams pay by deposit characteristics rather than ongoing value held: you reward **how long depositors commit**. You define duration tiers — each tier is a holding period with its own rate — and rewards for each tier unlock at its **cliff**, the end of that tier's window.
The tiers run **in series**, measured from each deposit's own arrival: with tiers of 14 days at 0 percent, 30 days at 3 percent, and 60 days at 5 percent, a deposit earns nothing over its first window, then each later tier's rate over that tier's window, claimable at the end of it. There is no mid-cliff claiming, and withdrawing before a cliff forfeits that tier's unvested rewards. The editor shows the **blended reward APR** across the full series and the total time to claim everything.
**Best for:** sticky liquidity — paying more to depositors who stay longer, without paying for hot money.
**Example:** you set three tiers: hold 14 days for 0 percent, 30 days for 3 percent, 60 days for 5 percent. A depositor who stays 60 days earns the blended rate across all three windows; one who leaves on day 20 earns only what vested at the first cliff.
Today the rate per tier reads as a percent APR (Fixed APR) or an amount per 1,000 USD per day (Fixed Rate). Tiering by **deposit size**, gap-fill rates, and a daily budget for deposit-based streams are visible in the flow but not yet available.
The estimated stream cost for a deposit-based stream assumes every deposit completes all tiers — it is the ceiling on what the stream can pay, not a forecast. The budget is allocated to deposits first in, first out, paying day by day while it lasts; when the budget runs out the stream stops.
## Airdrop
A manual or retroactive distribution with no automatic reward computation. You decide the allocations yourself and upload them through a dedicated snapshot endpoint — as a CSV or by tag. Use it to reward past activity or to run a one-off distribution on your own terms.
**Best for:** setting allocations by hand, rewarding retroactively, or running a one-time payout.
**Example:** you decide to reward 500 early depositors with a fixed grant each, based on a snapshot you took last month. You upload that allocation list and LPs claim against it. There is no continuous accrual.
Allocations are uploaded through a dedicated snapshot endpoint rather than computed from a rate. A single airdrop stream can carry multiple snapshots and payouts. See [Create a stream (API)](/sdk/streams/create-stream) and the [Streams API overview](/sdk/streams/overview) for how to submit them.
## Paying in points
Point streams pay units of a points program instead of a token. Because points have no market price until TGE, the mechanics that price the reward asset — Fixed APR and the gap-fill rates — are not available. Points support:
* **Fixed Rate:** a fixed number of points per 1,000 USD of TVL per day.
* **Daily Budget:** a flat daily pool of points, split pro-rata.
* **Airdrop:** a one-time points distribution defined by a recipient list.
Point amounts are denominated in points throughout; a dollar valuation is optional and never gates creation.
## Target your campaign
Whatever model you pick, the final configuration screen shapes who earns and how much: eligibility by deposit route (All Deposits, Turtle Only, or Select Distributors), whitelist and blacklist controls with OFAC screening on by default, percentage bonuses for linked X or Telegram accounts, referrals, and holders of a chosen asset, and reward forwarding to route a vault's earned rewards through to its underlying LPs. See the [overview](/partner-products/streams/overview#targeting-who-earns) for the full list and [Create a stream](/partner-products/streams/create-a-stream) for where each control appears in the flow.
# Claiming Rewards
Source: https://docs.turtle.xyz/partner-products/streams/claiming-rewards
Three ways your LPs can receive stream rewards: on Turtle, embedded in your own front end, or claimed for them automatically.
Every token stream pays out the same way under the hood. The backend commits a Merkle root of the latest reward snapshot on-chain, and a wallet presents a Merkle proof to the Stream contract to receive its balance. Claims are cumulative: one transaction always pays the full outstanding amount, and claiming when nothing new is owed simply transfers zero.
What you choose as a partner is where that claim happens. There are three paths, and they are not exclusive. Most campaigns start on Turtle and add an embedded or delegated flow later.
Claiming applies to **token streams** only. Point streams have no on-chain claim; points accrue off-chain and convert at a future TGE. Reward timing follows the reward type: TVL-based streams accrue continuously and each Merkle commit makes newly accrued rewards claimable, while deposit-based rewards become claimable at each cliff — there is no mid-cliff claiming.
## Pick a path
| Path | What you build | Best for |
| -------------------------- | --------------------------------------- | --------------------------------------------------------- |
| Through Turtle | Nothing | Getting live fast; campaigns where LPs already use Turtle |
| Embedded on your front end | A claim button in your own UI | Keeping LPs inside your product end to end |
| Delegated (auto-claim) | A backend service that claims for users | Gasless claiming, automation, custodial-style UX |
## 1. Through Turtle
The default. LPs connect their wallet on Turtle's app and claim their accrued rewards there. You do nothing beyond running the stream; Turtle hosts the claim UI, fetches the proofs, and submits the transactions from the LP's wallet.
This is the right starting point for every campaign. The other two paths are upgrades, not requirements.
## 2. Embedded on your own front end
If you want LPs to claim without leaving your site, embed the claim flow. It is a two-step integration: an API call, then an on-chain transaction signed by the user's wallet.
Call [`GET /v1/streams/merkle_proofs`](/sdk/streams/get-merkle-proofs) with the user's wallet address and your stream IDs. The endpoint is permissionless; no API key is needed. The response contains everything the claim needs: the cumulative amount, the proof array, the Stream contract address, and the root timestamp.
Call `canClaim()` on the Stream contract as a read-only call to display the user's unclaimed balance before they click claim. It accounts for previous claims automatically.
Call `claim(amount, timestamp, proof)` on the Stream contract with the values from the API. The user signs; rewards transfer straight to their wallet.
The API returns the timestamp as an ISO 8601 string, but the contract expects Unix epoch seconds. Convert it before every contract call: `Math.floor(new Date(timestamp).getTime() / 1000)`. This is the most common integration mistake.
If a user has rewards across several streams, claim them all in one transaction with `batchClaim()` on the StreamFactory instead of one transaction per stream.
The full integration guide, including contract ABIs, working code, and a drop-in React claim button, is in the API docs:
The permissionless proof endpoint: parameters, response fields, and how they map to the claim call.
Contract ABIs, claim and batch-claim code, and the prebuilt React component.
## 3. Delegated claiming (auto-claim)
For a fully managed experience, you can claim on behalf of your users: rewards land in their wallets without them signing anything, and you cover the gas. This runs on the StreamFactory's operator model.
A one-time on-chain approval: the user calls `toggleOperatorForUser()` on the StreamFactory to authorize your operator address. The same call revokes the approval later.
Your service fetches proofs from the same permissionless endpoint, then calls `batchClaimFor()` on the StreamFactory. Rewards transfer to the user's wallet, not yours.
`claim()` on the Stream contract can only be called by the user themselves. Delegated claiming always goes through the StreamFactory's `batchClaimFor()` with prior operator approval, so a user's rewards can never be claimed by an address they have not explicitly authorized.
This path suits wallets, exchanges, and platforms whose users expect rewards to just appear, and campaigns where claim gas would otherwise eat into small allocations. The operator calls and code are covered in [Claim Rewards](/sdk/streams/claim-rewards).
## Good to know
* **Claims are cumulative.** The proof amount is the user's total allocation to date. The contract releases only what has not been claimed yet, so LPs never need to claim on a schedule to keep up.
* **Claiming stays open after a stream ends.** Rewards committed on-chain remain claimable; ending or pausing a stream does not take anything away from LPs. See [Managing a Stream](/partner-products/streams/campaign-management).
* **New balances appear with each Merkle commit.** Rewards accrue continuously but become claimable when the next root is committed on-chain, roughly every 12 hours. For deposit-based streams, each tier's rewards join the claimable balance at that tier's cliff.
# Create a Stream
Source: https://docs.turtle.xyz/partner-products/streams/create-a-stream
Launch an incentive campaign from the Client Portal in a few steps.
This page walks through launching a stream end to end. There are two ways to do it. The no-code path runs entirely through the [Client Portal](https://dashboard.turtle.xyz) and is the focus here. If you would rather create streams from your own backend, the API path covers the same flow programmatically.
Before you start, confirm your organization is approved and has the `streams-create` permission, and (for token streams) that the creating wallet already holds enough reward token to cover the total plus the creation fee. See [Before you start](/partner-products/streams/before-you-start).
Decide the reward type and mechanic before you configure rates.
Build the request, get the signed transaction params, and broadcast it yourself.
## Create from the Client Portal
Go to [dashboard.turtle.xyz](https://dashboard.turtle.xyz) and connect the wallet you will create the stream from. For token streams this wallet pays the reward token and the creation fee, so connect the one that holds the funds on the right chain.
Reward token selection is currently supported on Ethereum, Base, Avalanche, BSC, and Sepolia. Make sure your wallet is on one of these chains before you continue.
From the Streams area, select **New Stream** to open the creation flow. The Streams overview page also shows every existing stream with its type, cost per \$1k of TVL per day, distributed and remaining balance, and health.
A stream pays either a reward token or points, never both — and pays for either value held, deposit commitment, or a one-off list.
* **Tokens:** pays a real ERC-20 on-chain. Budgets and rates read in dollars. The token must be an allowlisted reward token on a supported chain.
* **Points:** pays units of a points program — amounts read in points and can convert to tokens at a future TGE. Point streams are created instantly, with no on-chain transaction, no funding, and no creation fee.
Then pick the reward type: **TVL-Based** (holders earn continuously against their balance), **Deposit-Based** (reward how long depositors commit, through duration tiers), or **Airdrop** (a one-time distribution defined by a recipient list).
Choosing points removes the later approval and signing steps, since there is no on-chain creation transaction, and narrows the mechanics to those that need no token price (Fixed Rate, Daily Budget, Airdrop). See [Get tokens](/sdk/streams/get-tokens) and [Get points](/sdk/streams/get-points) for what is available.
The mechanic determines which rate field you fill in next. For TVL-based streams: **Fixed APR**, **Fixed Rate**, or **Daily Budget** under Standard Rewards, and **Target APR** or **Reference APR** under Gap-Fill Rates. For deposit-based streams you pick the deposit dimension (**Duration** — tiers by holding period; Size is coming soon) and how tier rates read (**Fixed APR** or **Fixed Rate**).
For the tradeoffs and how to pick, read [Choosing a reward model](/partner-products/streams/choosing-a-reward-model).
Pick the **target** — the opportunity or token whose on-chain balance is tracked to measure each wallet's contribution. Search by chain, by opportunity (with native APR and active TVL shown), by receipt token, or paste a contract address directly.
Then pick the **reward asset** — the allowlisted ERC-20 you pay out (or the points program for point streams). The target and the reward asset are independent and usually different.
The configuration screen depends on your mechanic. For Target APR you drag the target line above the native APY curve and pay only the gap; for deposit-based streams you build the duration tiers. All configurations share the same core inputs:
* **Rate:** the headline number for your mechanic — an APR, tokens per \$1k per day, a daily budget, a target APR, or per-tier rates.
* **Estimated TVL:** the TVL you expect to incentivise. Derived figures — the estimated stream cost and the implied reward APR — are computed from it and marked as estimates.
* **Duration:** how long the stream runs. Start and end dates are set on the review step.
The **Est. Stream Cost** panel shows the projected total in dollars and reward tokens, the distribution rate, the stream fee, and the **maximum duration** your budget supports. Streams are required to distribute a minimum of \$33.33 per day, so the maximum duration is your budget divided by that floor — the end date fills in from it automatically, and you can shorten it but not extend it past what the budget covers. For deposit-based streams, the estimated cost assumes every deposit completes all tiers.
The review screen sets the start and end dates and the audience controls:
* **Eligibility:** who can earn, by deposit route — **All Deposits**, **Turtle Only** (deposits made through the Turtle UI or any Turtle distributor), or **Select Distributors** (only deposits routed through distributors you choose).
* **Whitelist:** restrict to tagged wallets, or upload a CSV list. Setting a whitelist takes precedence — the blacklist is disabled while whitelist tags are set, and the flow shows that it is.
* **Blacklist:** **OFAC Sanctioned Wallets** (flagged by the Chainalysis Sanctions Oracle) are excluded by default; add **Blocked Tags** or upload a CSV list to exclude more.
* **Bonuses:** percentage boosts on top of the earned rate — linked **X** account, linked **Telegram** account, **Referral**, and **Asset-Holding Bonus**.
* **Reward Forwarding** (Advanced): redirect the stream's earned rewards to another address — for example, forwarding rewards earned by a vault address through to the vault's underlying LPs.
* **Spend Caps:** an optional **Max Budget** (a hard cap on total rewards — the stream ends early once fully spent) and, for TVL-based streams, an optional **Daily Cap** (daily spend never exceeds it, even if TVL grows past the estimate).
Check everything before you fund: for token streams, the creating wallet must already hold the full total amount plus the creation fee, and for gap-fill mechanics the configuration is locked at creation. A stream's total amount and duration cannot be increased after launch.
Select **Fund Stream**. For token streams, approve the reward token spend, then sign the `createStream` transaction — the Turtle backend issues a signature and your wallet submits the transaction to the StreamFactory. Funding and launching are a single action; streams are fully collateralized at creation, with all funds to be distributed added upfront. Point streams skip the on-chain step and are created immediately.
The stream is live. The indexer begins tracking target token balances, and the first reward snapshot lands within about 12 hours. Track participants and accrued rewards from the Streams overview and the [Distribution Dashboard](/partner-products/distribution-dashboard). Once the first Merkle root is committed, LPs can start claiming; see [Claiming rewards](/partner-products/streams/claiming-rewards) for the three ways to offer that.
Rewards accrue from creation, but the first claimable balance appears only once the first on-chain Merkle root is committed, roughly every 12 hours. For deposit-based streams, rewards become claimable at each cliff.
## Launching from a multisig (Safe)
If the creating wallet is a Safe, create the stream through the API rather than signing in the browser. Call [Create a stream](/sdk/streams/create-stream) to obtain the signed `txParams`, then submit the reward token approval and the `createStream` call from the Safe Transaction Builder to the StreamFactory for your chain.
The submitting Safe must match the expected sender encoded in the signed params, or the transaction will revert. Contract addresses and the full broadcast walkthrough are in [Create a stream](/sdk/streams/create-stream).
## Prefer to integrate programmatically?
Request bodies, signing, base-units rules, and the StreamFactory broadcast guide for every chain.
# Streams
Source: https://docs.turtle.xyz/partner-products/streams/overview
Self-serve, on-chain liquidity incentive campaigns that pay LPs for the TVL they contribute or the deposits they commit.
Streams is Turtle's liquidity incentive distribution product. A protocol creates a self-serve reward campaign (a stream) that pays tokens or points to liquidity providers based on their contribution to a target position. Contributions are tracked continuously, rewards are computed off-chain for flexibility, and each distribution is committed on-chain as a Merkle root so anyone can verify it. The contracts are non-custodial and were audited in January 2026.
If you run a vault, a pool, or any position you want LPs to deposit into and hold, a stream attaches a reward to that behavior without you building distribution infrastructure.
Two tokens matter in every stream. The **reward token** (or points) is what gets paid out. The **target token** is the token whose on-chain balance Turtle tracks to measure each wallet's contribution. They are usually different. See the [glossary](/resources/glossary).
## What you get
Self-serve creation from the Client Portal or the API. Pay for the TVL wallets hold or for how long depositors commit, with rate mechanics from a fixed cost per unit of TVL to gap-fill rates that only pay when native yield falls short. Audience targeting through eligibility, whitelists, and boosts. Pay in real tokens or in points that convert at a future TGE. Each stream holds its own funds and every distribution is verifiable on-chain.
Claim on their own schedule. A single cumulative claim always pays the full outstanding balance. Rewards stack on top of the vault's native yield. No lockup, and LPs keep custody of their position throughout.
## How a stream is defined
Three choices define every stream, made in order at creation:
1. **Reward base** — what you pay with: **Tokens** (an ERC-20 with a market price; budgets and rates read in dollars) or **Points** (units of a points program; amounts read in points and convert at a future TGE).
2. **Reward type** — what you pay for:
* **TVL-Based** pays by token value held. Holders earn continuously against their balance.
* **Deposit-Based** pays by deposit characteristics — rewarding how long depositors commit, through tiered rates that unlock at cliffs.
* **Airdrop** is a one-time distribution defined by a recipient list.
3. **Mechanic** — how the rate is set within that type (Fixed APR, Fixed Rate, Daily Budget, or a gap-fill rate). See the table below.
You may see older names for deposit-based streams — "Deposit Vesting", "Vesting Bonus", or "Deposit Ladder" in older material and dashboards. They are the same thing: deposit-based streams with duration tiers. In the API, gap-fill streams are still created under the `Yield Match` type; see the [create-stream reference](/sdk/streams/create-stream).
## How a stream works
Set the reward base, reward type, mechanic, target, rate, and schedule in the Client Portal or via the API. For token streams, the Turtle backend issues a signature and your wallet submits an on-chain `createStream` transaction to the StreamFactory. Point streams are created instantly, with no on-chain step.
The indexer tracks the target token balance of every holder and builds a time-series of TVL contributions. For deposit-based streams it also tracks each deposit and the route it arrived through, so eligibility can be scoped to deposits made through Turtle or through specific distributors.
A reward updater runs roughly twice daily and computes each wallet's accrued rewards from its contribution and the stream's mechanic, saved as snapshots.
The latest snapshot is committed as a Merkle root, roughly every 12 hours, which makes the distribution verifiable.
LPs submit a Merkle proof to claim. For TVL-based streams rewards accrue continuously and each commit makes newly accrued rewards claimable; for deposit-based streams rewards become claimable at each cliff. Claims are cumulative, so a single transaction always pays the full outstanding balance. Claiming can happen on Turtle, on your own front end, or automatically on the LP's behalf. See [Claiming rewards](/partner-products/streams/claiming-rewards).
Rewards begin accruing after creation, and the first snapshot lands within about 12 hours. For the full pipeline (indexer, snapshots, Merkle commitments, claim flow), see the [Streams API overview](/sdk/streams/overview).
## Rate mechanics at a glance
The mechanic decides how the per-wallet reward rate is set. Which mechanics are available depends on the reward type and base.
| Mechanic | What it does | Best for |
| ------------- | ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- |
| Fixed APR | A flat reward APR on top of the native rate, converted to a per-day token figure at each snapshot using current prices. | Advertising a headline APR. |
| Fixed Rate | A fixed amount of reward tokens per 1,000 USD of TVL per day — spend scales with the pool. | A predictable cost per unit of TVL. |
| Daily Budget | A flat amount per day split pro-rata across LPs — the APR it implies moves with TVL. | A fixed spend per day. |
| Target APR | Gap-fill: tops up to a floor whenever the native APY dips below it — you pay only the gap. | Guaranteeing depositors a minimum total yield. |
| Reference APR | Gap-fill: tracks another vault's rate plus an offset, paying only the shortfall. | Matching a competing vault's yield. |
| Airdrop | Manual or retroactive allocations you upload yourself; no automatic computation. | One-off or retroactive rewards. |
For deposit-based streams, the rate is set **per duration tier** (Fixed APR or Fixed Rate per tier today), and rewards for each tier unlock at its cliff. Point streams support the mechanics that need no token price: Fixed Rate, Daily Budget, and Airdrop. See [Choosing a reward model](/partner-products/streams/choosing-a-reward-model) to compare and pick.
## Token streams and point streams
A stream is either token-based or point-based, never both.
* **Token streams** pay a real ERC-20 on-chain. The reward token must be an allowed reward token, and your funding wallet must hold the tokens the stream distributes (plus the creation fee). Reward-token selection for creation is currently supported on Ethereum, Base, Avalanche, BSC, and Sepolia.
* **Point streams** track off-chain points that can convert to tokens at a future TGE. They are created instantly with no on-chain transaction, which makes them useful before a token exists. Point amounts are denominated in points; a dollar valuation is optional and never required.
Target tokens are supported on a broader set of chains than reward tokens. See [Before you start](/partner-products/streams/before-you-start) for funding and chain requirements.
## Targeting who earns
Streams shape who earns and how much through the final configuration screen, applied between the base reward computation and the final Merkle tree.
| Control | Effect |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Eligibility | Scope earning by deposit route: **All Deposits**, **Turtle Only** (deposits made through the Turtle UI or any Turtle distributor), or **Select Distributors** (only deposits routed through distributors you choose). |
| Whitelist | Restrict eligibility to tagged wallets, or upload a CSV list. A whitelist takes precedence: when whitelist tags are set, the blacklist is disabled, and the flow shows that it is. |
| Blacklist | Exclude wallets. **OFAC Sanctioned Wallets** (flagged by the Chainalysis Sanctions Oracle) are excluded by default, and you can block tagged wallets or upload a CSV list (**Blocked Tags**). |
| Bonuses | Percentage boosts on top of the earned rate: linked **X** account, linked **Telegram** account, **Referral** (referrer receives a share of referees' rewards), and **Asset-Holding Bonus** (holders of a chosen asset earn an extra percentage). |
| Reward Forwarding | Redirect a stream's earned rewards to another address — for example, forwarding rewards earned by a vault address through to the vault's underlying LPs. |
In the API these controls are configured through the `adapters` array at creation. See [Create a stream](/sdk/streams/create-stream) for the exact configuration.
## Where Streams is live
Streams runs on Ethereum, BSC, Avalanche, and Base, with Sepolia for testing. A new chain is added by deploying a StreamFactory and configuring an indexer webhook.
Streams are non-custodial. The StreamFactory deploys a separate Stream contract per campaign; each holds its own funds and exposes a permissionless claim. All admin operations are gated by an AccessManager owned by the Turtle multisig. The contracts were audited in January 2026. See the [audit reports](/resources/audits) and the [Streams API](/sdk/streams) for contract detail and addresses.
# Changelog
Source: https://docs.turtle.xyz/products/changelog
What shipped across Turtle products this week.
## Week of July 31, 2026
### Updates
**Refreshed hero image for the Q2 2026 report**
* The [Turtle Q2 2026: building the hub for onchain assets](https://turtle.xyz/blog/turtle-q2-2026-building-hub-onchain) quarterly report on [turtle.xyz](https://turtle.xyz) now uses a higher-resolution hero banner for a cleaner read on desktop and mobile.
***
***
## Week of July 24, 2026
### New features
**Redesigned homepage at turtle.xyz**
* [turtle.xyz](https://turtle.xyz) has been rebuilt around a new "Onchain Yield Management" story with an animated 3D hero scene and dedicated calls to action for **Investors** ([app.turtle.xyz](https://app.turtle.xyz)) and **Asset Issuers** ([dashboard.turtle.xyz](https://dashboard.turtle.xyz)).
* Live network stats (TVL, active campaigns, and other metrics) continue to sit in the hero and refresh with current activity.
**Command Center section**
* A new home section pitches Turtle as a single command center for onchain yield, highlighting three capabilities:
* **Diligenced Deals** — curated onchain yield backed by Turtle review, clear mechanics, and transparent incentive terms. See [Turtle Deals](/liquidity-products/turtle-deals).
* **Aggregated Portfolio** — bundle wallets across DeFi to evaluate positions and discover idle assets.
* **Personalized Alerts** — get pinged when a new deal fits your book and stay on top of active positions.
**Yield pipeline overview**
* A new five-step section walks through how Turtle helps you **Discover → Analyze → Invest → Monitor → Manage** onchain yield end-to-end, so partners and LPs can see the full workflow from opportunity sourcing to position management.
### Updates
**Refreshed case studies and social proof**
* Case studies now spotlight recent programs including Avalanche liquidity deployment, the Katana network bootstrap, and Decibel's \$10M-in-24-hours campaign, with clearer visuals and metrics.
* The homepage adds a refreshed "Backed By" partner marquee and updated team section.
**Latest updates feed on the homepage**
* The homepage now surfaces a "Latest updates" section that links directly to recent blog posts, making it easier to catch product announcements without leaving turtle.xyz.
**Talk-to-team modal on the new home**
* The launch and contact CTAs across the new homepage open the shared talk-to-team modal, matching the flow introduced on the [liquidity portal](https://turtle.xyz/liquidity) last week.
***
***
## Week of July 17, 2026
### New features
**New liquidity portal on turtle.xyz**
* The old liquidity page has been replaced with a dedicated liquidity portal at [turtle.xyz/liquidity](https://turtle.xyz/liquidity), featuring a redesigned layout, portal widget, and header treatment tuned for institutional partners.
* A new lead inquiry form captures partner interest and routes submissions to the team automatically.
* Launch CTAs across the site now scroll directly to the inquiry section for a cleaner path to contact.
* Learn more about liquidity programs in [Turtle Deals](/liquidity-products/turtle-deals) and [Turtle Vaults](/liquidity-products/turtle-vaults).
**Refreshed blog and editor experience**
* The public blog now lives under the landing layout with a shared header and footer, so navigation stays consistent across [turtle.xyz](https://turtle.xyz), blog posts, and the portal.
* The `/editor`, upload, and preview routes were restyled to match the landing design system.
### Updates
**Persistent header with updated CTAs**
* The site header is now pinned across landing routes and no longer flashes on navigation between pages.
* The primary header CTA has been renamed to **Open App** (with **Open Portal** on liquidity views), and a **TurtleOS** link is now surfaced on desktop.
* Mobile header polish: fixed the logo blink on load, removed tap focus rings, and hid the TurtleOS pill where it was crowded.
**Live hero stats on home and liquidity**
* Hero network metrics on the home and liquidity pages now load client-side and refresh with current activity.
* The standalone "Turtle Network" stats row was removed to keep the hero focused.
**Improved lead form**
* The talk-to-team modal now opens directly from any launch CTA without scrolling.
* Email and required-field validation messages are clearer, and the mobile modal layout has been tightened.
### Bug fixes
* Fixed hero stats occasionally rendering blank due to a removed backend field.
* Fixed the gradient heading rendering in older Chromium-based browsers.
* Fixed liquidity header pill styling and letter spacing in the navbar.
* Removed a stale partner logo and various dead code paths that could cause layout jitter.
***
## Week of July 10, 2026
### Updates
**Refreshed homepage on turtle.xyz**
* The "Backed by" investor section is now hidden on [turtle.xyz](https://turtle.xyz) so the homepage focuses on product, pipeline, and case studies.
* Team member listings on the homepage were updated to reflect current names.
* No action needed — the changes are live for anyone visiting the site.
***
## Week of July 7, 2026
### Updates
**Live network stats on turtle.xyz**
* The homepage hero now displays live totals for TVL, active campaigns, and other network metrics pulled from Turtle's overview API instead of static values.
* Numbers reflect current on-chain activity and refresh automatically as new deposits, streams, and campaigns come online.
* See the network overview in the [Turtle app](https://app.turtle.xyz) for the same data in-product.
***
Looking for API-level changes? See the [Turtle API changelog](/sdk/reference/changelog).
# Before You Start
Source: https://docs.turtle.xyz/products/deals/before-you-start
Prerequisites and the decisions to settle before you launch a liquidity campaign.
A liquidity campaign is relationship-sourced, so launching one runs through the Turtle team rather than a fully self-serve form. This page is a preflight check. Run through it before you open the Client Portal so you are not stopped by a missing agreement, an unfinished diligence review, or terms you have not decided yet. If you already know what a liquidity campaign is, skip ahead to [Launch a Liquidity Campaign](/products/deals/launch-a-deal). If you are new, start with the [Liquidity Campaigns overview](/liquidity-products/turtle-deals).
## Prerequisites
Your organization must be created and approved in the [Client Portal](https://dashboard.turtle.xyz). Creating an org also starts a know-your-business (KYB) check and an integration fee invoice. See [Client Portal setup](/partner-products/overview-partners).
A master services agreement (MSA) is signed during org setup, before any liquidity campaign goes live. The commercial terms of a specific liquidity campaign are then settled in a separate statement of work (SOW) at the end of the flow.
If you do not see liquidity campaign submission in the Client Portal, your org is likely not approved yet or the MSA is not signed. Reach out to the Turtle team before going further.
Two gates must clear before a liquidity campaign moves into committee review: KYB clearance through the provider Turtle uses, and payment of the integration fee invoiced at org creation.
The vault you want to incentivize must be a contract type Turtle already integrates. If it is not yet supported, the liquidity campaign can still proceed through diligence and terms, but it queues at signing until the integration ships.
## The diligence gate
Every liquidity campaign is reviewed before it goes live. The [Turtle Due Diligence Council](/resources/turtle-due-diligence-council) (TDC) is an independent body that evaluates the vault and the protocol across technical, operational, financial, and curator risk. The council operates independently of Turtle's commercial team, so a liquidity campaign can be declined on diligence grounds regardless of the commercial relationship.
In parallel, a review committee works through the diligence data you submit and iterates with you until every item is resolved. The liquidity campaign does not advance to a signed SOW until that review is complete.
Where a TDC review has been completed, a written report is published alongside the vault listing. To learn what the council evaluates and how to engage it, see the [Turtle Due Diligence Council](/resources/turtle-due-diligence-council).
## Decisions to make before you launch
Have answers to these ready before submission. Each maps to a field or a term you will set during the flow.
The token your protocol will use to fund the boost. The budget you commit in this token is what pays LPs the extra rewards on top of base yield.
How much extra LPs earn, above the vault's native yield, for the liquidity they contribute. The rate is set when the campaign is structured and funded from your emission budget.
When the liquidity campaign starts and how long it runs. The incentive window begins at campaign go-live, not per individual LP deposit, so Turtle Network TVL is measured from the go-live date forward.
Which vault or vaults the incentive applies to. Only deposits into eligible vaults earn the incentive and count toward Turtle Network TVL.
How Turtle Network TVL is scoped. The default charges on campaign-specific Turtle Network TVL (wallets that engaged with Turtle infrastructure for this opportunity), with broader models available where Turtle drives more of the protocol's growth. This choice changes who counts toward the fee, so settle it before terms. See [Pricing](/resources/pricing) for the three models.
## Commercial terms
A liquidity campaign carries a fee on Turtle Network TVL, charged by reconciling two ledgers (who qualifies, and how much TVL those wallets hold in the target opportunity). The exact rate sits in your SOW, but the model, the Turtle Network TVL definitions, and the example fee bands are documented on the [Pricing](/resources/pricing) page. Read it before the terms are structured so they are not new to you at signing.
## If your protocol or vault is not yet supported
If your vault's contract type is not yet integrated, or you are unsure whether your protocol fits, reach out to the Turtle team through the [Client Portal](https://dashboard.turtle.xyz). A liquidity campaign can move through diligence and terms while an integration is built, then go live once it ships.
# Launch a Liquidity Campaign
Source: https://docs.turtle.xyz/products/deals/launch-a-deal
Submit, structure, and launch a liquidity campaign through the Client Portal.
This page walks through launching a liquidity campaign end to end. Unlike a stream, a liquidity campaign is not a one-click self-serve action: you submit campaign details in the [Client Portal](https://dashboard.turtle.xyz), the liquidity campaign clears a diligence gate, you settle terms with the Turtle team, and the liquidity campaign goes live once a statement of work is signed. The arc below is the known sequence; where the exact Portal screens are still being confirmed, the step says so.
Before you start, confirm your organization is approved with a signed master services agreement, KYB cleared, and the integration fee paid, and that you have decided your emission token, incentive rate, duration, and eligible vaults. See [Before you start](/products/deals/before-you-start).
The prerequisites and the terms to decide before submission.
The fee model you will structure against, with example bands.
## Submit a liquidity campaign from the Client Portal
Go to [dashboard.turtle.xyz](https://dashboard.turtle.xyz) and open the organization you want to launch the liquidity campaign under. Liquidity campaign submission is only available once your org is approved and the master services agreement is signed.
A liquidity campaign sits inside a campaign. Provide the campaign-level details first: the protocol, the networks involved, and a description of what you are running.
If you have run a liquidity campaign before, you can seed a new one from a prior liquidity campaign in your org and edit from there, rather than re-entering everything.
Specify the terms of the liquidity campaign itself: the emission token, the incentive rate, the duration, and which vaults are eligible. These are the decisions from [Before you start](/products/deals/before-you-start).
The target vault must be a contract type Turtle already integrates. If it is not, the liquidity campaign can still proceed through the rest of the flow and queues at signing until the integration ships.
Complete the diligence section so the review committee and the [Turtle Due Diligence Council](/resources/turtle-due-diligence-council) can evaluate the liquidity campaign. This covers the vault and protocol across technical, operational, financial, and curator risk. Some fields are canonical at the org level (audits, oracle provider, token information) and carry across liquidity campaigns once entered.
Diligence data entry unlocks only after KYB has cleared and the integration fee is paid. If those gates are not met, this step is blocked.
The review committee works through your diligence submission and iterates with you until every item is resolved. In parallel, the Turtle team negotiates the commercial terms against the [Pricing](/resources/pricing) model: the attribution scope and the fee on Turtle Network TVL. This is a back-and-forth with the team, not a Portal-only step.
The council reviews independently of Turtle's commercial team. A liquidity campaign can be declined on diligence grounds regardless of the commercial relationship.
Once diligence is resolved and terms are agreed, a statement of work (SOW) is signed. The SOW is where the specific fee rate and the liquidity campaign's commercial terms are fixed.
After the SOW is signed and any pending integration has shipped, the liquidity campaign goes live. It appears as a featured opportunity in the [Turtle app](https://app.turtle.xyz), eligible vaults are labeled, and Turtle Network TVL is measured from the go-live date forward. Track performance from the [Liquidity Campaigns dashboard](/partner-products/deals-dashboard).
The incentive window begins at campaign go-live, not at each LP's deposit. Attribution starts counting Turtle Network TVL from that point.
# Before You Start
Source: https://docs.turtle.xyz/products/earn/before-you-start
Prerequisites and the decisions to make before you route your first attributed deposit.
This page is a preflight check. Run through it before you start integrating so you are not stopped by a missing organization, an API key you do not have yet, or an integration path that does not fit your product. If you already know how distribution works, skip ahead to [Configure opportunities](/products/earn/configure-opportunities). If you are new, start with the [Distribution overview](/partner-products/distribution/overview).
## Prerequisites
Your organization must be set up and approved as a distribution partner in the [Client Portal](https://dashboard.turtle.xyz). Organization setup is required for both integration paths.
Your distributor ID is the identifier every deposit is attributed to. One organization can have more than one distributor, for example a separate ID for your web and mobile surfaces. Find your distributor ID in the [Distribution Dashboard](/partner-products/distribution-dashboard).
If you integrate through the Earn API, you need a publishable API key scoped to your organization. Share links do not require an API key. Create and manage keys as described in [API keys](/sdk/authentication/api-keys).
Use a publishable key (`pk_live_`) for client-side calls. Keep secret keys server-side only. The canonical auth header is being confirmed.
Decide which opportunities you want to put in front of users. Share links work only with Turtle featured deals; the Earn API covers the full catalog. See [Configure opportunities](/products/earn/configure-opportunities).
## Decisions to make before you launch
Have answers to these ready before you integrate.
Share links are no-code. You attach your distributor ID to a featured-deal URL and share it; the user lands on the deposit page and attribution happens automatically. Best for KOLs, newsletters, content creators, and non-technical partners.
The Earn API lets you build the deposit experience inside your own product. You generate the deposit and withdrawal transactions and your users sign them in your interface. Best for wallets, apps, and platforms. The two paths are not exclusive; you can run share links today and add the API later.
See [Share links](/partner-products/share-links) for the no-code path and the [Turtle Earn API](/sdk/earn/quickstart) for the API path.
You choose which opportunities from the Turtle catalog to surface, and you can tailor the set to your audience, for example stablecoin vaults only or a single chain. Have a shortlist before you launch.
[Configure opportunities](/products/earn/configure-opportunities) walks through browsing the catalog and configuring your set.
Deposits made through the Earn API require the user to be a registered Turtle member. If you build the API path, plan where membership registration fits in your flow. Share links handle this inside the Turtle app, so you do not build it yourself.
See [Register a wallet](/sdk/authentication/register-wallet) for the membership flow.
## If you are not approved or your opportunity is not supported
If your organization is not yet approved as a distributor, or the opportunity you want to offer is not in the catalog, reach out to the Turtle team through the [Client Portal](https://dashboard.turtle.xyz).
# Configure Opportunities
Source: https://docs.turtle.xyz/products/earn/configure-opportunities
Pick which Turtle opportunities to put in front of your users, and keep the set current.
Configuring your set is choosing which opportunities your users see. Turtle has a large catalog of vaults and campaigns across many chains, and most distributors do not want to show all of it. You pick a set that fits your audience, a few stablecoin vaults for a conservative newsletter, a single chain for a chain-native wallet, or whatever matches what your users want, and that set is what they deposit into.
There are two ways to configure, matched to your integration path. The no-code path runs through the Client Portal and share links; the API path lets you fetch and serve your configured set programmatically. This page covers both at altitude and links DOWN to the API reference for the exact request and response.
Before you start, make sure your organization is approved and you have a distributor ID. See [Before you start](/products/earn/before-you-start).
See the featured deals available to share, with live TVL and APR.
Query the full catalog or your distributor-filtered set programmatically.
## Browse the catalog
Turtle's opportunities are vaults and campaigns a user can deposit into. Each carries the data you configure against: the underlying asset, the chain, the protocol, current TVL, an estimated APR, the incentives attached, and whether it is a Turtle featured deal.
The featured deals are listed at [app.turtle.xyz/earn/opportunities](https://app.turtle.xyz/earn/opportunities), where you can see each deal's asset, chain, and live numbers. For the full catalog and the exact fields you can filter and sort on, use the API. See [Get opportunities](/sdk/opportunities/get-opportunities) for the catalog endpoint, its filters, and the full opportunity shape.
## Configure for share links
If you use share links, the opportunities you can put in front of users are the Turtle featured deals.
Share links work only with Turtle featured deals, the opportunities listed on [app.turtle.xyz/earn/opportunities](https://app.turtle.xyz/earn/opportunities). A non-featured opportunity or an external vault URL will not carry your distributor ID, so the deposit is not attributed to you.
To configure for share links, pick the featured deals that fit your audience and build a link for each one. Each link is the deal's page with your distributor ID attached. See [Share links](/partner-products/share-links) for the link format, examples, and how to verify a deposit was attributed to you.
## Configure through the API
If you integrate through the Earn API, you configure your set by selecting which opportunities your product shows and serving them from the catalog endpoint. You can:
* Pull the full catalog and filter it to the chains, assets, or opportunity types your audience wants.
* Pull only your distributor's configured set, so your product shows exactly the opportunities you have selected for your distributor ID.
Both come from the same opportunities endpoint, scoped differently. The distributor-scoped query returns the set tied to your distributor ID. See [Get opportunities](/sdk/opportunities/get-opportunities) for the filters, the distributor-scoped variant, and the full response fields.
Where you configure a distributor's set in the Client Portal is part of the Distribution Dashboard. See the [Distribution Dashboard](/partner-products/distribution-dashboard) for the screen.
## Keep your selections current
Opportunities change. TVL moves, an APR shifts, incentives start and end, and an opportunity can be paused or wound down. Review your configured set on a cadence that fits your audience so you are not pointing users at a deal that no longer earns what it used to or is no longer active.
When you query opportunities, each one carries a status. Drop or replace anything that is no longer active before it reaches your users. The status field and the rest of the opportunity shape are documented on [Get opportunities](/sdk/opportunities/get-opportunities).
# Deposit and Withdraw
Source: https://docs.turtle.xyz/products/vaults/deposit-and-withdraw
Deposit into a Turtle vault, deposit with any token you hold, handle a pending deposit, and withdraw, all from the Turtle app.
This page walks you through putting funds into a vault and taking them back out, entirely from the [Turtle app](https://app.turtle.xyz). No code. If you want to do the same thing from your own backend, the deposit endpoint covers it programmatically; there is a link at the bottom.
## Before you start
You need three things in place before you deposit.
Any self-custody wallet you control. Turtle never holds your funds; it builds each transaction and you sign it from your wallet.
Your funds and your wallet should be on a chain Turtle supports. The app shows each vault's chain, and you can filter the catalog by chain. See the chain list on the [Yield Opportunities overview](/liquidity-products/turtle-vaults).
Some flows require your wallet to be a registered Turtle member before a deposit goes through. The app prompts you to register if it is needed.
## Deposit from the Turtle app
Go to [app.turtle.xyz](https://app.turtle.xyz) and connect the wallet you want to deposit from.
Browse the catalog and filter by chain, deposit token, APY, or TVL until you find a vault you want. Open it to see its details, including whether it carries an active liquidity campaign or Streams reward.
Enter how much you want to deposit. If you hold the vault's native token, deposit it directly. If you hold a different token, the app can convert it for you as part of the deposit (see [Deposit with any token](#deposit-with-any-token) below).
The APY shown is the vault's current rate. Any liquidity campaign or Streams rewards stack on top and are tracked separately. See [Track your rewards](/products/vaults/track-your-rewards).
Approve the token spend if your wallet prompts for it, then confirm the deposit. Your wallet signs; the funds move on-chain to the vault.
For an instant vault, your position is active right away. For an async vault, the deposit may still be pending; finish it from the app once it is ready (see [When a deposit completes later](#when-a-deposit-completes-later)).
## Deposit with any token
You do not have to hold a vault's native token to deposit into it. If you hold a different supported token, the app converts it for you in the same flow: you choose the token you have, and Turtle routes the swap before the deposit lands. You end up with a position in the vault, having spent the token you started with.
This is the same capability the API calls **swap mode**. As an LP, all it means is one fewer step: deposit with what is in your wallet instead of swapping first yourself.
A conversion is subject to slippage, the small price movement between quote and execution. The app shows the expected result before you confirm.
## When a deposit completes later
Some vaults (the async type, used by protocols like Mellow and Lagoon) do not settle a deposit in one transaction. The vault queues your request and processes it a little later. While it is pending, you have two choices:
* **Claim it** once the vault has processed it, to finish the deposit and activate your position.
* **Cancel it** if you change your mind before it settles, to get your funds back.
You do both from the app, from the pending deposit itself.
## Withdraw
Find the vault position you want to exit in your portfolio in the app.
Choose how much to withdraw, then confirm. Your wallet signs the transaction.
For an instant vault, funds return to your wallet in the same transaction. For an async vault, the withdrawal may be queued and settle a little later.
# Track Your Rewards
Source: https://docs.turtle.xyz/products/vaults/track-your-rewards
Where to see your accrued vault yield, leaderboard points, Liquidity Campaign rewards, and Streams rewards as a liquidity provider.
A single vault deposit can earn you up to four things at once: the vault's base yield, leaderboard points, Liquidity Campaign rewards, and Streams rewards. They accrue in different ways and show up in different places. This page is the map.
Everything here is read from the [Turtle app](https://app.turtle.xyz) using the same wallet you deposited with. You do not register anything separately; rewards attach to your deposit automatically.
## Vault yield
The base yield from the vault's underlying protocol accrues to your position continuously. You see it in your portfolio in the app, where the position reflects the value it has earned.
## Leaderboard Shells
Depositing into eligible vaults earns you Turtle Shells toward the [Liquidity Leaderboard](/liquidity-products/leaderboard). Shells accrue from the value you deposit, with boosts for referred liquidity, social connections, and staking. Your rank and Shell total live on the leaderboard page in the app.
For the full scoring rules and what counts, see the [Liquidity Leaderboard](/liquidity-products/leaderboard).
## Liquidity Campaign rewards
If you deposited into a vault with an active [Liquidity Campaign](/liquidity-products/turtle-deals), you earn additional token emissions on top of the base yield, in proportion to the liquidity you contributed over the campaign period. Liquidity Campaign rewards are calculated when the campaign settles and distributed afterward, rather than streaming to you in real time.
## Streams rewards
If a vault you are in has an active [Streams](/partner-products/streams/overview) campaign, you earn that stream's reward token or points in proportion to your TVL contribution over time. Streams rewards accrue continuously and become claimable as each on-chain snapshot lands.
When a campaign lets you claim through Turtle, you connect your wallet in the app and claim your accrued balance there. Claims are cumulative, so a single claim always pays the full outstanding amount.
## How to claim
When a Streams campaign lets you claim through Turtle, the whole process happens in the app and takes three steps.
Open the [Turtle app](https://app.turtle.xyz) and connect the same wallet you deposited with. Rewards are tied to that wallet, so claiming from a different one shows nothing to claim.
Go to the rewards area for your portfolio. Each claimable balance is listed with the token or points you have earned and the amount available.
Click claim and confirm the transaction in your wallet. Claims are cumulative, so a single claim always pays the full outstanding amount. Balances that are committed on-chain stay claimable even after a campaign ends.
For partners building their own claim flow: how stream rewards are claimed through Turtle, embedded in a partner's app, or claimed for users automatically.
## Good to know
* Rewards stack. One deposit can earn vault yield, points, a liquidity campaign, and a Stream at the same time, with no extra steps from you.
* Points and rewards attach to the wallet you deposited with. Use that wallet to view and claim.
* Streams rewards stay claimable after a campaign ends; what is committed on-chain remains yours to claim. See [Claiming rewards](/partner-products/streams/claiming-rewards).
# Audit Reports
Source: https://docs.turtle.xyz/resources/audits
Independent security audits of Turtle's smart contracts.
Turtle's smart contracts are reviewed by independent security firms. The reports below are the canonical record.
* [Drip Contract Audit 10/18/25](https://drive.google.com/file/d/1vsfYioACulqb17qgNKXHKjDSbj_WDT60/view?usp=sharing)
* [Contract Audit 09/29/25](https://drive.google.com/file/d/1vsfYioACulqb17qgNKXHKjDSbj_WDT60/view?usp=sharing)
* [Streams Contract Audit (Cantina)](https://drive.google.com/file/d/17-KHHhgcOTUVI6JcwTLvhoWp7lrNTyJP/view?usp=sharing)
# Brand Kit
Source: https://docs.turtle.xyz/resources/brand-kit
Turtle logos, colors, and usage rules for partners and press.
This page has the Turtle logos, brand colors, and usage rules for referencing Turtle in your own product, deck, or article. Use the marks as supplied. Do not use them in a way that implies Turtle endorses your product unless we have agreed to that in writing.
## Logos
Turtle ships in two forms: a standalone mark (the icon on its own) and a full logo (the mark with the wordmark). Pick the variant that has contrast against your background.
*Full logo on light backgrounds.*
*Full logo on dark backgrounds.*
| File | Use |
| -------------------------------------------- | ----------------------------------------------- |
| `Full-NinjaBlack.png`, `Full-NinjaBlack.svg` | Full logo on light backgrounds. Prefer the SVG. |
| `Full-WhiteWise.png`, `Full-WhiteWise.svg` | Full logo on dark backgrounds. Prefer the SVG. |
| `turtle-logo-black.png` | Mark only, for light backgrounds. |
| `turtle-logo-white.png` | Mark only, for dark backgrounds. |
| `light.png`, `dark.png` | Theme variants for light and dark interfaces. |
Use the SVG files wherever your medium supports vectors. They stay sharp at any size. Reach for the PNG files only when a raster image is required.
## Colors
The Turtle palette is built around a single green. Use the primary for brand surfaces and calls to action. The light and dark variants are for hover, accents, and contrast.
| Color | Hex | Use |
| ------------- | --------- | ---------------------------------------------------------- |
| Primary green | `#15A323` | Brand surfaces, primary buttons, accents. |
| Light green | `#06C94E` | Hover states, highlights, lighter accents. |
| Dark green | `#14801F` | Pressed states, text on light backgrounds, deeper accents. |
## Logo usage
Keep clear space around the logo so nothing crowds the mark. Scale it proportionally. Place the dark logo on light backgrounds and the light logo on dark backgrounds.
Do not recolor the logo. Do not stretch, skew, or rotate it. Do not add effects. Do not place the light logo on a light background or the dark logo on a dark background.
## Attribution for partners
If you embed a Turtle Earn or Streams claim UI inside your own product, follow these rules so users understand where the experience comes from.
Display a "Powered by Turtle" credit on any surface that embeds a Turtle Earn or Streams claim UI.
Link the credit to [turtle.xyz](https://turtle.xyz).
Attribution credits the technology. It does not mean Turtle endorses, audits, or vouches for your product. Do not state or imply otherwise.
Any Turtle mark you display must follow the logo and color guidance on this page.
Building a claim UI or distribution into your product? See [Distribution](/partner-products/distribution/overview) and the [Streams overview](/partner-products/streams/overview) for what these surfaces do.
## Download
The full media kit, with logos and additional assets, is available as a single archive.
Turtle Club Media Kit (zip).
# Glossary
Source: https://docs.turtle.xyz/resources/glossary
# **Turtle Glossary**
*Key terms and definitions across the Turtle platform*
## **Core Users and Entities**
**Liquidity Provider (LP)**
Turtle's userbase is made of liquidity providers who deposit into the selected list of vaults and liquidity campaigns brought by the Turtle network.
**Organization**
An organization describes a partner protocol, service provider, or distributor within Turtle’s ecosystem.
**Client (or Partner Protocol)**
Clients make liquidity campaigns with Turtle to attract liquidity by offering a combination of liquidity campaigns and/or leaderboards.
**Distribution Partner**
Partners who distribute liquidity campaigns on their frontend and earn revenue for the liquidity they provision.
**TurtleDAO**
The decentralized autonomous organization that encompasses all token holders, partners, users, and builders. Controls the treasury and protocol governance.
**TurtleDAO Treasury**
The protocol’s reserve of interest-bearing and yield-generating assets accumulated from partner protocol contributions and fees.
**[Turtle.Club](http://Turtle.Club) Association**
The legal entity (Swiss Verein in Zug) that operates the protocol and executes governance decisions.
## **Products & Offerings**
**Webapp**
Turtle's LP interface for liquidity management, depositing, diligence, and \$TURTLE token management.
**Partner Portal**
Also known as the Client Portal or Dashboard, the Partner Portal encompasses Turtle’s B2B offering and includes incentive tools, distribution tools, outreach tools, and admin functions.
**Incentive Tools**
Turtle offers protocols incentive tools to attract liquidity. These tools include Products, Liquidity Campaigns, Streams, and Leaderboards. All tools include customizable parameters to define a campaign that meets their needs.
**Distribution Tools**
The distribution suite offers partners a dashboard and toolkit for those who want to earn a revenue share by attracting liquidity for Liquidity Campaigns. They do this by sharing a distributor link or integrating directly in their own frontend.
**Outreach Tools**
Turtle’s outreach tools include Turtle Chat, Turtle LP Search, Drip Campaign, and Turtle CRM.
**Product**
A Product details the high-level information of a liquidity offering. Products define the top-line explanation for a liquidity campaign and can hold one or more liquidity campaigns.
**Opportunity**
An Opportunity is a selected liquidity campaign, vault, smart contract, or token that generates rewards for LPs within the Turtle network.
**Leaderboard**
Turtle’s liquidity leaderboard offers a gamified UI that encourages LPs to compete against the rest to earn top place. These leaderboards often include customizable boosts for auxiliary activities, and they distribute extra incentives on top of the daily rewards included in a given opportunity.
**API Boost (Turtle Boosts)**
Turtle’s first core product. Structures additional token/point shares for Turtle users based on aggregate incentives, tracked via APIs and on-chain indexed data, without additional trust assumptions.
**Yield Opportunities**
Automated yield products that pool assets and route them into desired chains, markets, and dApps via selected infrastructure partners.
**Turtle Campaigns (Ecosystem-as-a-Service)**
Helps clients tap into Turtle’s network of stakeholders to structure ecosystems, lower cost of capital, and align stakeholders.
**Earn SDK**
A white-label product that allows distribution partners to showcase Liquidity Campaigns on their own frontends and earn a revenue share on user liquidity volumes.
**Attribution**
The process by which deposits are linked on-chain to the distribution partner that sourced them. Attribution is automatic and requires no manual reporting from the partner.
**Distributor ID / Distributor Link**
The unique identifier or referral link used by distribution partners to track liquidity they bring and earn revenue share.
**Liquidity Campaigns**
Selected yield opportunities available through the Turtle protocol. Each liquidity campaign has completed a TDC review and carries a published diligence report.
**Turtle Due Diligence Council (TDC)**
An independent body established to bring structured review standards to vaults and liquidity campaigns on the Turtle protocol. Where a TDC review has been completed a written diligence report is published. The TDC is actively expanding its coverage across the protocol.
## **Incentives & Yield**
**Incentives**
Covers the span of rewards distributed for LPs to generate yield, including points, tokens, native yield, and additional rewards.
**Native Yield**
Comes from fees generated via protocol activity (like lending and trading).
**Additional Rewards**
Often defines a point or token reward distributed by a protocol.
**Streams**
A new way to distribute and track points or tokens directly via the Turtle platform. The system utilizes both onchain and offchain systems to define user holdings and USD value of specific ERC20 token contracts on a 12-hour basis.
**Liquidity Repurposing**
The ability for LPs to generate multiple contributions with the same liquidity by deploying across multiple partner protocols, triggering additional rewards at each layer.
**Turtle Referral Code**
Referral links that earn additional Turtle points for both the referrer and the referred LP.
## **Streams Terms**
These expand on the brief Streams entry under Incentives and Yield. For the product walkthrough see [Streams Overview](/partner-products/streams/overview), and for request formats and parameters see the [Streams API reference](/sdk/streams).
**Stream** One incentive campaign. A stream pays a reward token or points to liquidity providers for the TVL they contribute or the deposits they commit, tracked continuously. A partner configures a stream once (reward base, reward type, mechanic, target, rate, duration) and LPs accrue and claim against it for its lifetime. "Campaign" is an acceptable synonym.
**Reward Type** What a stream pays for, chosen at creation: **TVL-Based** (pays by token value held — holders earn continuously against their balance), **Deposit-Based** (pays by deposit characteristics — rewarding how long depositors commit through duration tiers that unlock at cliffs), or **Airdrop** (a one-time distribution defined by a recipient list). Older material may call deposit-based streams "Deposit Vesting" or "Vesting Bonus". See [Choosing a Reward Model](/partner-products/streams/choosing-a-reward-model).
**Mechanic (Stream Type)** The rule that decides how much each LP earns within a reward type: Fixed Rate (tokens per 1,000 USD of TVL per day), Fixed APR (an annualized percentage converted to tokens at each snapshot), Daily Budget (a fixed daily pool split pro-rata), and the gap-fill rates Target APR and Reference APR. Deposit-based streams set their rate per duration tier. The mechanic is chosen at creation. See [Choosing a Reward Model](/partner-products/streams/choosing-a-reward-model).
**Cliff** The end of a duration tier's window in a deposit-based stream. Each tier covers a consecutive window measured from the deposit, pays its rate over that window, and its rewards become claimable only at the cliff. Cliffs run in series and there is no mid-cliff claiming.
**Target Token** The token whose on-chain balance is tracked to measure each wallet TVL contribution. The indexer watches holders of the target token, and the size of a wallet position determines its share of rewards. This is distinct from the reward token. Target tokens are supported on a broader set of chains than reward tokens.
**Reward Token** The token actually paid out to LPs. For token streams this is a real ERC-20 transferred on-chain at claim time. Reward token selection at creation is currently supported on Ethereum, Base, Avalanche, BSC, and Sepolia, and the token must be an allowed reward token.
**Token Stream** A stream whose rewards are a real ERC-20. The creating wallet holds enough of the reward token to cover the total plus the creation fee, and submits an on-chain createStream transaction to the StreamFactory. A stream is either token-based or point-based, never both.
**Point Stream** A stream that pays off-chain points rather than tokens. Point streams are created instantly with no on-chain step, and points can convert to tokens at a future TGE. See [Create a Point Stream](/sdk/streams/create-point).
**Snapshot** A saved record of each wallet accrued rewards at a point in time. The reward updater writes snapshots so that accrual is preserved and auditable, and the latest snapshot is what gets committed on-chain.
**Reward Updater** The off-chain job that computes accrued rewards. It runs about twice per day, reads each wallet TVL contribution and the stream rate, and saves the result as a snapshot. Computing rewards off-chain keeps stream types flexible while on-chain commitment keeps them verifiable.
**Merkle Root** A single hash that summarizes the latest snapshot of all wallet balances. Turtle commits the Merkle root on-chain roughly every 12 hours, which makes the distribution verifiable without storing every balance on-chain.
**Merkle Proof** The data an LP submits to prove their entry is part of the committed Merkle root. The proof lets the Stream contract confirm an amount is owed and release it. See [Get Merkle Proofs](/sdk/streams/get-merkle-proofs).
**Cumulative Amount** The total an LP is owed since the stream began, not the delta since their last claim. Because amounts are cumulative, a single claim transaction always pays the full outstanding balance and there is no need to claim from every snapshot.
**StreamFactory** The on-chain contract that deploys a new Stream contract for each campaign. It also supports batch and delegated claiming. New chains go live by deploying a StreamFactory and configuring an indexer webhook. Contract addresses per chain are in [Create a Stream](/sdk/streams/create-stream).
**Stream Contract** The per-campaign contract deployed by the StreamFactory. Each one holds its own funds, accepts Merkle root commitments from a restricted backend role, and exposes a permissionless claim that anyone can call to pay an owed LP.
**AccessManager** The contract, owned by the Turtle multisig, that gates all admin operations across the Streams contracts. It is the control point for privileged actions. The contracts were audited in January 2026; see [Audits](/resources/audits).
**Boost Plugin (Adapter)** An optional rule applied between base reward computation and the final Merkle tree to adjust who earns and how much. Six are live: Turtle User, X (Twitter), Telegram, Whitelist, Blacklist, and Forwarder. Plugins are configured through the adapters array; see [Create a Stream](/sdk/streams/create-stream).
**Forwarder** A boost plugin that forwards rewards earned by a vault address to the underlying LPs of that vault, for example a Euler Earn Vault. It is used when the holder of the target token is a contract rather than the end depositor.
**Target APR** A gap-fill mechanic. You set a target APR and the stream pays only the difference between that target and the vault's native APY, measured against a trailing average over a lookback window (7 days, 1 month, 3 months, or 6 months) — a vault yielding 4 percent against a 4.75 percent target pays the gap, and a vault that meets or beats the target pays nothing (the boost is never negative). Supersedes the earlier names "Yield Floor" and "Guaranteed APR". In the API it runs under the `Yield Match` type with `targetApy` set. See [Choosing a Reward Model](/partner-products/streams/choosing-a-reward-model).
**Reference APR** A gap-fill mechanic that tracks another vault's rate plus an optional offset, paying only the shortfall between that reference and the target's native yield. Supersedes the earlier name "reference rate" for this mechanic. In the API it runs under the `Yield Match` type with `targetApy` unset and an optional `apyOffset`. See [Choosing a Reward Model](/partner-products/streams/choosing-a-reward-model).
**Yield Match** The API-level type (`type = 5`) under which both gap-fill mechanics run: Target APR (with `targetApy` set) and Reference APR (without). The configuration is locked at creation. See [Create a Stream](/sdk/streams/create-stream).
**Claim** The action an LP takes to receive owed rewards. The LP submits a Merkle proof to the Stream contract, which verifies it against the committed root and releases the tokens. Claims can be made anytime and are cumulative, so one transaction settles the full balance. See [Claim Rewards](/sdk/streams/claim-rewards).
## **Network & Liquidity Metrics**
**Total Value Locked (TVL)**
The total liquidity value tracked across Turtle’s network of connected wallets and partner protocols.
**Current TVL**
A wallet's TVL in a given token or protocol as of the latest block. A point-in-time balance: it does not incorporate attribution, vesting, or deposit-history tracking.
**Turtle Network TVL**
Deposits that have come in through the Turtle API or SDK under any distributor ID. This is the basis Liquidity Campaign fees are charged on, scoped per campaign to the eligible vaults from the go-live date. Previously called qualified TVL. See [Pricing](/resources/pricing) for more details.
**Turtle Organization TVL**
Deposits attributed to any distributor ID attached to the Turtle organization itself.
**Turtle App TVL**
Deposits attributed to the specific distributor ID used on [app.turtle.xyz](https://app.turtle.xyz).
**Distribution TVL**
The total liquidity value of all wallets/links in the distribution layer.
## **Scoring & Leaderboard Mechanics**
**Liquidity Score**
A weighted measure of on-chain capital participation, representing 50% of leaderboard scoring.
**Distribution Score**
Verified deposits routed through Distributor IDs, representing 50% of scoring with a 10x multiplier.
**Boost Multipliers (Adaptors)**
Additional scoring bonuses for verified engagement activities (e.g., social media, Telegram).
**Turtle Shells**
The unit that ranks users on the current [Liquidity Leaderboard](/liquidity-products/leaderboard). Shells accrue continuously at deposit time and replace the earlier Distribution Score used in Season 1.
**Turtle Points**
An alternate name for the current leaderboard unit. Any reference to "Turtle Points" maps to Turtle Shells on the current leaderboard.
## **Token & Governance**
**TURTLE Token**
The ERC-20 governance and utility token with a fixed supply of 1 billion. Used for staking, governance voting, and ecosystem participation.
**sTURTLE**
Staked TURTLE tokens that activate governance voting power. Users must delegate sTURTLE to themselves or a Turtle Delegate to vote.
**Token Generation Event (TGE)**
The launch event for the TURTLE token, establishing initial circulating supply and beginning vesting schedules.
**Sablier**
Third-party on-chain vesting infrastructure used for all TURTLE token vesting schedules, providing transparent and auditable streaming contracts.
**Epoch**
A defined time period at the end of which partner protocols send agreed-upon emissions to TurtleDAO for distribution to LPs.
# Pricing and commercial models
Source: https://docs.turtle.xyz/resources/pricing
How each Turtle product is priced: who pays, the cost shape, and where to learn more.
Turtle has one commercial principle and several products that apply it differently. Protocols pay to attract liquidity. Distributors earn a share of what their liquidity generates. LPs pay nothing to Turtle. This page covers each product's model at a high level; for the exact configuration of any one, follow the link in that section.
This page is for the protocol or distributor deciding whether to work with Turtle and wanting to know what it will cost or pay before they read the product details.
## At a glance
**Attract liquidity (you pay)**
| Product | Who pays | Cost shape | Where to learn more |
| ------------------- | ------------ | ----------------------------------------------------------------- | -------------------------------------------------------------- |
| Liquidity Campaigns | The protocol | A fee on Turtle Network TVL over time, set per liquidity campaign | This page, below |
| Streams | The protocol | Creation fee plus the funded reward budget | [Before you start](/partner-products/streams/before-you-start) |
**Distribute (you earn)**
| Product | Who pays | Cost shape | Where to learn more |
| ------------ | --------------- | -------------------------------- | ------------------------------------------------------- |
| Distribution | Funded by yield | Revenue share to the distributor | [Distribution](/partner-products/distribution/overview) |
## Liquidity Campaigns: charging on Turtle Network TVL
Turtle charges Liquidity Campaigns on **net new Turtle Network TVL** using a deterministic, auditable attribution system. To keep it auditable and avoid subjective reconciliation, Turtle runs two parallel ledgers:
* **Ledger A: Attribution Ledger**
* **Ledger B: TVL Ledger**
Fees are calculated by reconciling these two ledgers against a campaign-specific whitelist of eligible wallets.
Records wallet interaction with:
* The Turtle front end
* A Turtle Earn SDK-integrated front end
* (If applicable) an approved distributor front end
A wallet that meets the selected engagement criteria is added to a **campaign-specific whitelist**.
Ledger A determines *who qualifies*.
Tracks:
* The Total Value Locked (TVL) of whitelisted wallets
* Within the specified protocol/opportunity
* From the campaign go-live date forward
Turtle charges on TVL over time, not deposit/withdrawal flow. This removes manipulation risk, looping behavior, and cross-interface complexity. TVL is objectively verifiable at the protocol level.
### Defining "Turtle Network TVL"
For each opportunity, the two ledgers are reconciled with one another. Ledger A tells us who to refine Ledger B down by. Ledger A can take different parameters to widen or reduce the scope of whitelisted users; Ledger B always remains as is.
The reconciliation process:
1. **Attribution List:** identify qualified wallets from Ledger A (qualified whitelist).
2. **TVL Figures:** pull TVL of those wallets from Ledger B (Turtle Network TVL).
### Attribution list configuration (Ledger A parameters)
This is how the scope of users is refined. For most projects Turtle charges on the default model of campaign-specific Turtle Network TVL. For projects Turtle is more involved in or that are earlier stage, it charges on all Turtle Member TVL. For projects where Turtle is instrumental to growth, it charges on all TVL.
Measures growth only from wallets that engaged with Turtle infrastructure (front end or SDK) for the specific opportunity after the launch date.
"Did this user deposit to this opportunity through Turtle?"
**When used:** the default institutional standard, where attribution must be strictly infrastructure-verifiable and opportunity-specific.
Measures growth from verified Turtle member wallets, excluding balances that existed prior to membership, after the launch date.
"Is this user a Turtle member?"
**When used:** when Turtle contributes meaningful distribution across its member base but is not the sole driver of total protocol growth.
Measures total protocol growth from the listing date, regardless of wallet source, after the launch date.
"All users were made aware of this through Turtle."
**When used:** where the bulk of protocol launch, distribution, and capital formation is driven exclusively by Turtle.
### Fee structure
Fees are applied to Turtle Network TVL. The rate and the introductory window are set per liquidity campaign in the commercial agreement. The incentive window begins at campaign go-live, not per LP deployment.
In a dispute, Ledger A provides whitelist qualification evidence and Ledger B provides protocol-level TVL snapshots (every 12 hours). The reconciliation is auditable and reproducible.
## Streams: creation fee plus reward budget
A Streams campaign is self-serve, so the protocol funds it directly rather than being billed on TVL after the fact. The cost has two parts: a one-time **creation fee** and the **reward budget** you fund, which is the total amount of tokens the campaign pays out over its run. The creating wallet must already hold both before the stream starts. Point streams have no on-chain funding and no creation fee.
The exact creation fee, funding rules, and how the budget relates to your chosen reward model are documented on the Streams pages, not restated here so there is one source of truth.
Funding prerequisites and the budget decisions to make first.
The creation flow, including the fee and total on the review screen.
## Earn: distributor revenue share
Distributors do not pay Turtle. They earn. A distributor that routes liquidity into Turtle vaults earns a share of the yield generated by the deposits attributed to it, paid out as recurring revenue share for as long as that TVL stays.
Revenue share rates are configured per distributor in the Client Portal rather than published as a single public rate, so they are not listed here.
How distribution and revenue share work, and how to get set up.
# Support
Source: https://docs.turtle.xyz/resources/support
How to reach the Turtle team for support.
You can join our [Discord server](https://discord.turtle.xyz) to submit support tickets.
# Turtle Due Diligence Council
Source: https://docs.turtle.xyz/resources/turtle-due-diligence-council
The independent body that brings structured review standards to DeFi yield opportunities on Turtle.
The Turtle Due Diligence Council (TDC) is an independent body established to bring structured review standards to DeFi yield opportunities. The TDC is actively formalizing its review process and coverage across the Turtle protocol.
For how the TDC fits into Turtle's broader safety posture, see [Trust and Security](/get-started/trust-and-security).
## What the TDC does
The council evaluates vaults and deals across four risk dimensions:
* **Technical risk:** smart contract quality, audit history, upgrade mechanisms
* **Operational risk:** team background, custody model, operational controls
* **Financial risk:** collateralization, liquidity profile, historical performance
* **Curator risk:** track record, conflicts of interest, disclosure practices
Where a TDC review has been completed, a written report is published alongside the vault listing.
## Independence
Council members operate independently of Turtle's commercial team. A vault or deal can be declined by the TDC regardless of the commercial relationship between Turtle and the protocol.
## Published reports
Where a diligence report has been completed it is published and accessible via the vault's Transparency page. For featured vaults the TDC works with [Accountable](https://accountable.finance) to produce an independent Proof of Solvency.
## Contact
Protocols seeking to engage the TDC for a review should contact the Turtle team through the [Client Portal](https://dashboard.turtle.xyz) or reach out directly at [turtle.xyz](https://turtle.xyz). As the council scales coverage, review criteria and methodology will be published here.
# Distributor Metrics
Source: https://docs.turtle.xyz/sdk/analytics/distributor-metrics
TVL and LP-count time-series attributed to a distributor (builder code).
Send your API key via the `X-API-Key` header. See [Authentication](/sdk/authentication/api-keys).
## Overview
Track the TVL and liquidity-provider counts attributed to a distributor over time. The `distributorId` is your builder code. Deposits routed through it are attributed on-chain by Lumon, and Turtle's own attributed volume is just another distributor ID, so the same endpoints work for any distributor you query.
| Endpoint | Returns |
| ------------------------------------------------- | ----------------------------------------------------------------------- |
| `GET /v2/metrics/distributor/{distributorId}` | TVL time-series, per-opportunity TVL as-of latest, optional top wallets |
| `GET /v2/metrics/distributor/{distributorId}/lps` | Active and cumulative LP counts over time |
## Distributor TVL
```bash curl theme={null}
curl -X GET "https://earn.turtle.xyz/v2/metrics/distributor/your-distributor-id?startDate=2026-05-01T00:00:00Z&endDate=2026-05-31T00:00:00Z&step=86400" \
-H "X-API-Key: pk_live_xxxxx"
```
```typescript TypeScript theme={null}
const res = await fetch(
'https://earn.turtle.xyz/v2/metrics/distributor/your-distributor-id?' +
new URLSearchParams({ startDate: '2026-05-01T00:00:00Z', endDate: '2026-05-31T00:00:00Z', step: '86400' }),
{ headers: { 'X-API-Key': 'pk_live_xxxxx' } }
);
const { timeseries, asOf } = await res.json();
```
**Path Parameters**
The distributor ID (builder code) to report on.
**Query Parameters**
Start of range, RFC 3339 (e.g. `2026-05-01T00:00:00Z`).
End of range, RFC 3339.
Bucket size in seconds. Defaults to `900` (15 minutes). Use `86400` for daily.
Optional. Restrict to specific opportunity UUIDs.
Optional. Restrict to specific product UUIDs.
When `true`, include the top 50 wallets by attributed TVL.
**Response**
```json theme={null}
{
"timeseries": [
{ "timestamp": "2026-05-30T00:00:00Z", "tvl": "2400000.0000" }
],
"asOf": [
{ "opportunityId": "550e8400-e29b-41d4-a716-446655440000", "asOf": "2026-05-30T00:00:00Z" }
],
"topWallets": [
{ "walletAddress": "0xe84ef330b7b5c02fb3fbe05f2a31cb331c2b874c", "totalTvl": "300000.0000", "asOf": "2026-05-30T00:00:00Z" }
]
}
```
TVL bucketed by `step`. Each point has a `timestamp` and a decimal `tvl`.
Per-opportunity latest data timestamp within the range (`opportunityId`, `asOf`).
Present only when `includeTopWallets=true`. Top 50 wallets by attributed TVL, with `walletAddress`, `totalTvl`, and `asOf`.
## LP counts
```bash curl theme={null}
curl -X GET "https://earn.turtle.xyz/v2/metrics/distributor/your-distributor-id/lps?startDate=2026-05-01T00:00:00Z&endDate=2026-05-31T00:00:00Z&step=86400" \
-H "X-API-Key: pk_live_xxxxx"
```
Takes the same `startDate` / `endDate` / `step` / `opportunityIds` / `productIds` parameters as the TVL endpoint.
**Response**
```json theme={null}
{
"timeseries": [
{ "timestamp": "2026-05-30T00:00:00Z", "activeLps": 274, "participatedLps": 318 }
]
}
```
Distinct wallets with TVL greater than 0 in the bucket.
All-time cumulative wallets that have ever had TVL attributed to this distributor.
# API Keys
Source: https://docs.turtle.xyz/sdk/authentication/api-keys
Authenticate with the Turtle Earn API using publishable and secret keys.
Every Earn API endpoint requires an API key, passed on the `X-API-Key` header. Use the key issued when your organization was created, or contact the Turtle team if you need one. Store it securely.
## Key types
There are two key types, distinguished by prefix.
The publishable key (`pk_live_`) is safe in client-side and browser code. It covers read access to opportunities, deposit and wallet activity, and the verify endpoint.
The secret key (`sk_live_`) is server-side only. It is required for write operations such as generating deposit and withdrawal transactions, creating memberships, and managing streams.
Never expose your `sk_live_` key in client-side code, browsers, or public repositories. Treat it like a database password.
### Publishable key
```bash curl theme={null}
curl https://earn.turtle.xyz/v2/opportunities/ \
-H "X-API-Key: pk_live_xxxxx"
```
```typescript TypeScript theme={null}
const res = await fetch('https://earn.turtle.xyz/v2/opportunities/', {
headers: { 'X-API-Key': 'pk_live_xxxxx' },
});
```
### Secret key
Use this from your backend only. The example below builds a deposit, a write action that the publishable key cannot perform. See [Deposit](/sdk/earn/deposit) for the full request and response.
```bash curl theme={null}
curl -X POST "https://earn.turtle.xyz/v2/actions/deposit/{opportunityId}" \
-H "X-API-Key: sk_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{ "userAddress": "0x1234...", "tokenIn": "0xA0b8...", "amount": "1000000", "distributorId": "your-distributor-id", "mode": "direct" }'
```
```typescript Node.js theme={null}
const res = await fetch(
`https://earn.turtle.xyz/v2/actions/deposit/${opportunityId}`,
{
method: 'POST',
headers: {
'X-API-Key': process.env.TURTLE_SECRET_KEY!,
'Content-Type': 'application/json',
},
body: JSON.stringify({
userAddress: '0x1234...',
tokenIn: '0xA0b8...',
amount: '1000000',
distributorId: 'your-distributor-id',
mode: 'direct',
}),
}
);
```
## Rate limits
Rate limit state is returned in response headers. The budget is per key and resets hourly.
| Header | Description |
| ----------------------- | ------------------------------------ |
| `X-RateLimit-Limit` | Hourly cost unit budget |
| `X-RateLimit-Remaining` | Cost units remaining this hour |
| `X-RateLimit-Used` | Cost units consumed this hour |
| `X-Monthly-Limit` | Monthly cost unit cap, if configured |
| `X-Monthly-Usage` | Cost units consumed this month |
| `X-Monthly-Remaining` | Cost units remaining this month |
When a limit is exceeded, the API returns `429 Too Many Requests`.
## Next steps
A valid key is only half of access control. Action endpoints also require the user's wallet to be a registered Turtle member. See [Register Wallet](/sdk/authentication/register-wallet) for the membership flow.
# Register Wallet
Source: https://docs.turtle.xyz/sdk/authentication/register-wallet
Connect wallets and create memberships in Turtle
All requests require an API key via the `X-API-Key` header.
See [Authentication](/sdk/authentication/api-keys) for details.
## Overview
Before a wallet can interact with any action endpoint, it must be registered as a Turtle member. Membership links a wallet address to a Turtle user, which is what enables deposit attribution and revenue tracking. Supported ecosystems are EVM (Ethereum, Arbitrum, Base, and every supported EVM chain), Solana, and TON.
The Membership API follows a three-step flow that proves wallet ownership: check membership, request a sign-in message, then submit the signed message.
Action endpoints reject an unregistered wallet.
## Authentication Flow
Verify if a wallet address is already associated with a Turtle account
Generate a message that must be signed by the wallet to prove ownership
Submit the signed message to create a new user account and associate the wallet
## Endpoints
### Check Membership Status
`GET /v2/membership/`
```bash curl theme={null}
curl -X GET "https://earn.turtle.xyz/v2/membership/?address=0xaD595ba34B6BEdCdFDecCe0C0cDe6A2Dc7Ad658D&walletEcosystem=evm" \
-H "X-API-Key: pk_live_xxxxx"
```
```typescript TypeScript theme={null}
const response = await fetch(
'https://earn.turtle.xyz/v2/membership/?address=0xaD595ba34B6BEdCdFDecCe0C0cDe6A2Dc7Ad658D&walletEcosystem=evm',
{ headers: { 'X-API-Key': 'pk_live_xxxxx' } }
);
const data: { isMember: boolean } = await response.json();
```
**Query Parameters**
The wallet address to check
The blockchain ecosystem. Supported values: `evm`, `solana`, `ton`
#### Response Example
```json theme={null}
{
"isMember": false
}
```
#### Response Fields
Whether the wallet address is already associated with a Turtle account.
### Request Signature Agreement
`POST /v2/membership/agreement`
```bash curl theme={null}
curl -X POST https://earn.turtle.xyz/v2/membership/agreement \
-H "X-API-Key: pk_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"address": "0xaD595ba34B6BEdCdFDecCe0C0cDe6A2Dc7Ad658D",
"walletEcosystem": "evm",
"url": "https://turtle.xyz",
"chainId": "1"
}'
```
```typescript TypeScript theme={null}
const response = await fetch('https://earn.turtle.xyz/v2/membership/agreement', {
method: 'POST',
headers: { 'X-API-Key': 'pk_live_xxxxx', 'Content-Type': 'application/json' },
body: JSON.stringify({
address: '0xaD595ba34B6BEdCdFDecCe0C0cDe6A2Dc7Ad658D',
walletEcosystem: 'evm',
url: 'https://turtle.xyz',
chainId: '1',
}),
});
const data: { nonce: string; message: string } = await response.json();
```
**Request Body**
The wallet address requesting membership
The blockchain ecosystem. Supported values: `evm`, `solana`, `ton`
The URL of the application (used in the signature message)
The chain ID for EVM wallets. Not required for Solana or TON
#### Response Example
```json theme={null}
{
"nonce": "550e8400-e29b-41d4-a716-446655440000",
"message": "turtle.xyz wants you to sign in with your Ethereum account:\n0xaD595ba34B6BEdCdFDecCe0C0cDe6A2Dc7Ad658D\n\nSign Up to Turtle\n\nURI: https://turtle.xyz\nVersion: 1\nChain ID: 1\nNonce: 550e8400-e29b-41d4-a716-446655440000\nIssued At: 2024-01-15T10:00:00Z"
}
```
#### Response Fields
A single-use nonce that must be included when submitting the signed message.
The [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) sign-in message the wallet must sign to prove ownership.
### Create Membership
`POST /v2/membership/`
```bash curl theme={null}
curl -X POST https://earn.turtle.xyz/v2/membership/ \
-H "X-API-Key: pk_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"address": "0xaD595ba34B6BEdCdFDecCe0C0cDe6A2Dc7Ad658D",
"walletEcosystem": "evm",
"signature": "0x1234567890abcdef...",
"nonce": "550e8400-e29b-41d4-a716-446655440000",
"distributorId": "your-distributor-id"
}'
```
```typescript TypeScript theme={null}
const response = await fetch('https://earn.turtle.xyz/v2/membership/', {
method: 'POST',
headers: { 'X-API-Key': 'pk_live_xxxxx', 'Content-Type': 'application/json' },
body: JSON.stringify({
address: '0xaD595ba34B6BEdCdFDecCe0C0cDe6A2Dc7Ad658D',
walletEcosystem: 'evm',
signature: '0x1234567890abcdef...',
nonce: '550e8400-e29b-41d4-a716-446655440000',
distributorId: 'your-distributor-id', // optional
}),
});
const data: { isMember: boolean; error: string } = await response.json();
```
**Request Body**
The wallet address creating the membership
The blockchain ecosystem. Supported values: `evm`, `solana`, `ton`
The signature of the message returned by the agreement endpoint
The nonce returned by the agreement endpoint
The distributor ID to associate the membership with. When provided, the user will be tracked as having signed up through the distributor's integration.
#### Response Example
```json theme={null}
{
"isMember": true,
"error": ""
}
```
#### Response Fields
Whether the wallet is now a registered Turtle member.
An error message when the request fails, or an empty string on success.
## Complete Flow Example
Here's a complete example of the membership creation flow:
```bash curl theme={null}
# Step 1: Check if wallet is already a member
curl -X GET "https://earn.turtle.xyz/v2/membership/?address=0xaD595ba34B6BEdCdFDecCe0C0cDe6A2Dc7Ad658D&walletEcosystem=evm" \
-H "X-API-Key: pk_live_xxxxx"
# Response: {"isMember": false}
# Step 2: Request signature agreement
curl -X POST https://earn.turtle.xyz/v2/membership/agreement \
-H "X-API-Key: pk_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"address": "0xaD595ba34B6BEdCdFDecCe0C0cDe6A2Dc7Ad658D",
"walletEcosystem": "evm",
"url": "https://turtle.xyz",
"chainId": "1"
}'
# Response: {"nonce": "550e8400...", "message": "turtle.xyz wants you to sign..."}
# Step 3: Sign the message with your wallet (using web3 library or wallet app)
# This step happens client-side
# Step 4: Submit the signature to create membership
curl -X POST https://earn.turtle.xyz/v2/membership/ \
-H "X-API-Key: pk_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"address": "0xaD595ba34B6BEdCdFDecCe0C0cDe6A2Dc7Ad658D",
"walletEcosystem": "evm",
"signature": "0x1234567890abcdef...",
"nonce": "550e8400-e29b-41d4-a716-446655440000"
}'
# Response: {"isMember": true, "error": ""}
# Step 5: Verify membership was created
curl -X GET "https://earn.turtle.xyz/v2/membership/?address=0xaD595ba34B6BEdCdFDecCe0C0cDe6A2Dc7Ad658D&walletEcosystem=evm" \
-H "X-API-Key: pk_live_xxxxx"
# Response: {"isMember": true}
```
## Error Handling
### Common Errors
**Status Code:** 400 Bad Request
**Response:**
```json theme={null}
{
"error": {
"status": "INVALID_ARGUMENT",
"error": "invalid wallet ecosystem"
}
}
```
**Solution:** Use one of the supported ecosystems: `evm`, `solana`, or `ton`
**Status Code:** 400 Bad Request
**Response:**
```json theme={null}
{
"error": {
"status": "INVALID_ARGUMENT",
"error": "invalid wallet address"
}
}
```
**Solution:** Ensure the wallet address is valid for the specified ecosystem
**Status Code:** 409 Conflict
**Response:**
```json theme={null}
{
"error": {
"status": "ALREADY_EXISTS",
"error": "wallet already exists"
}
}
```
**Solution:** This wallet is already associated with an account. You do not need to create a new membership.
**Status Code:** 400 Bad Request
**Response:**
```json theme={null}
{
"error": {
"status": "INVALID_ARGUMENT",
"error": "invalid nonce or expired"
}
}
```
**Solution:** Request a new agreement and sign it promptly. Nonces expire after a short period
## Security Considerations
Never share your private keys or seed phrases. The API only requires signatures, not private keys.
* Nonces are single-use and expire after a short period
* Messages follow the [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) standard for EVM wallets
* All signatures are verified server-side before creating accounts
# Deposit Modes
Source: https://docs.turtle.xyz/sdk/concepts/deposit-modes
Two things vary per opportunity: which token a deposit accepts, and whether it settles in one step or asynchronously
Two properties of an opportunity decide how a deposit behaves. They are independent of each other.
* **Input token**: does the vault take its own deposit token directly, or will the API swap another token in for you? This is the direct vs swap distinction.
* **Settlement**: does the deposit complete in one transaction, or does it queue and require a follow-up claim? This is the instant vs async distinction.
Read both off the opportunity object before you build the deposit. For the why and the partner-facing framing, see the [Distribution overview](/partner-products/distribution/overview).
## Direct vs swap
Direct and swap are the two values of the `mode` field on a deposit request.
| Mode | What it does | Available when |
| -------- | ------------------------------------------------------------------------------------------------ | ----------------------------------------- |
| `direct` | The user deposits the vault's native token directly. | `meta.directInteractionEnabled` is `true` |
| `swap` | The user supplies a different input token and the API routes it through a DEX before depositing. | `meta.routedSwapEnabled` is `true` |
Both flags can be `true` on the same opportunity, in which case you choose the mode. Both can describe the same vault from opposite ends:
| Scenario | `meta.directInteractionEnabled` | `meta.routedSwapEnabled` |
| -------------------- | ------------------------------- | ------------------------ |
| Direct deposit only | `true` | `false` |
| Swap deposit only | `false` | `true` |
| Both modes available | `true` | `true` |
Swap mode adds one parameter, `slippageBps`, the maximum acceptable slippage in basis points. The exact request shape for both modes, including how `slippageBps` defaults and bounds, is on [Deposit](/sdk/earn/deposit).
## Instant vs async
Most vaults settle a deposit in a single transaction. Some, including Mellow and Lagoon, queue the deposit and require a second step once the vault processes it.
| Settlement | What happens | What you do next |
| ---------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------ |
| Instant | The deposit transaction completes the position in one shot. | Nothing. The position is live. |
| Async | The deposit enters a pending state in the vault. | Wait for the vault to process it, then claim to finalize (or cancel to abort). |
Detect this by reading the boolean settlement flags off the opportunity object:
* `meta.asyncDeposit` is `false`: the deposit completes in a single transaction.
* `meta.asyncDeposit` is `true`: the deposit needs a separate claim step after the vault processes the request. `meta.asyncWithdraw` signals the same for withdrawals.
For the claim and cancel flow on an async deposit, see [Async Deposits](/sdk/earn/async-deposits).
## Putting it together
The two axes combine freely. An opportunity can be direct + instant, swap + instant, direct + async, or swap + async. Resolve both before generating the deposit:
Check `meta.directInteractionEnabled` and `meta.routedSwapEnabled` to decide whether you can deposit the user's token directly or need swap mode.
Check `meta.asyncDeposit` to know whether to expect a follow-up claim.
Set `mode`, and if async, plan for the claim step. See [Deposit](/sdk/earn/deposit) and [Async Deposits](/sdk/earn/async-deposits).
# Distributor Model
Source: https://docs.turtle.xyz/sdk/concepts/distributor-model
How Turtle scopes API calls to a distributor and attributes deposits automatically
Every Earn API call is scoped to a distributor. The distributor is what white-labels vault discovery, ties deposits back to your integration, and drives revenue share. This page is the canonical reference for that model. For the product-level story of who distribution is for and how the commercial relationship works, see the [Distribution overview](/partner-products/distribution/overview).
## Video walkthrough
A quick recap of how anyone can become a distributor and use the API.
## What is a distributor
A distributor is an integration point that embeds Turtle vault opportunities into a product. Each distributor has a unique `distributorId` that scopes endpoint responses to that integration and tags the deposits it generates.
## Distributor vs organization
An **organization** is the top-level entity that manages billing, team members, and settings. A **distributor** sits within an organization and represents one specific integration, with its own API keys, opportunity selection, and attribution tracking.
One organization can have multiple distributors. A wallet product might run one distributor for its mobile app and a separate one for web, each with a different opportunity set configured in the [Dashboard](https://dashboard.turtle.xyz).
## How attribution works
You never call an endpoint to record attribution. It happens on-chain, automatically, off the deposit you generate.
When you generate a deposit transaction with your `distributorId`, Turtle embeds that ID into the transaction calldata as a tracking signature.
Turtle monitors the supported chains and detects transactions that carry a tracking signature.
The detected deposit is attributed to your distributor account. No manual call is required.
The `POST /v1/actions/attribute` endpoint has been removed. Attribution is fully automatic. There is no endpoint to call to record it.
To confirm a specific transaction carries your tracking signature, use [Verify Attribution](/sdk/earn/verify-attribution). To pull the full list of deposits attributed to your distributor, use [Distributor Activity](/sdk/earn-api/deposits).
## Distributor-scoped opportunities
Each distributor has a set of opportunities configured in the [Dashboard](https://dashboard.turtle.xyz). Fetch only the opportunities enabled for your integration:
```bash theme={null}
GET /v2/opportunities/distributors/{distributorId}
```
This returns the same Opportunity objects as the full catalog, filtered to your selection, so users only see the vaults you have approved. See [Get Opportunities](/sdk/opportunities/get-opportunities) for the full object reference and the distributor-scoped endpoint.
## Share links
You can attribute deposits without any API integration. Append your `distributorId` to any opportunity URL as a query parameter:
```
https://app.turtle.xyz/earn/opportunities/{slug}?distId={your_distributor_id}
```
Deposits made through that link trigger the same on-chain attribution as an API-generated deposit. See [Share Links](/partner-products/share-links) for the no-code guide.
## Revenue share
Distributors earn a share of the yield generated by the users they onboard. Rates are configured per distributor in the [Dashboard](https://dashboard.turtle.xyz) and revenue is tracked off the deposits attributed to your `distributorId`.
# Distributor Activity
Source: https://docs.turtle.xyz/sdk/earn-api/deposits
Retrieve deposit activity attributed to your distributor
All requests require an API key via the `X-API-Key` header.
See [Authentication](/sdk/authentication/api-keys) for details.
## Overview
`GET /v2/deposit/{distributorId}`
Retrieve paginated deposit activity attributed to a specific distributor. Results are ordered by date descending. You can filter by opportunity or product to narrow results. This is the API behind the deposit feed in the [Distribution Dashboard](/partner-products/distribution-dashboard).
Looking for wallet-scoped activity across all distributors? See [Wallet Activity](/sdk/portfolio/activity) for deposits and withdrawals by wallet address. To choose between the three views, see the [Portfolio & Activity overview](/sdk/portfolio/overview).
## Endpoint
### Get Distributor Activity
```bash curl theme={null}
curl -X GET "https://earn.turtle.xyz/v2/deposit/your-distributor-id?page=1&limit=20" \
-H "X-API-Key: pk_live_xxxxx"
```
```typescript TypeScript theme={null}
const response = await fetch(
'https://earn.turtle.xyz/v2/deposit/your-distributor-id?page=1&limit=20',
{ headers: { 'X-API-Key': 'pk_live_xxxxx' } }
);
const data = await response.json();
```
## Path Parameters
The unique identifier of the distributor to retrieve deposits for.
## Query Parameters
Filter deposits to a specific opportunity.
Filter deposits to opportunities belonging to a specific product. When combined with `opportunityId`, the opportunity must belong to the product; otherwise an empty page is returned.
Page number for pagination.
Number of deposits per page (max: 100).
## Response Example
```json theme={null}
{
"deposits": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"opportunityId": "550e8400-e29b-41d4-a716-446655440000",
"interaction": "deposit",
"txHash": "0xedfdf71e0e4daec5afcb87988821a8bccd5c282647c8e81a65a71181a44a8e51",
"chainId": 1,
"blockTimestamp": "2025-10-08T16:18:07Z",
"walletAddress": "0xe84ef330b7b5c02fb3fbe05f2a31cb331c2b874c",
"amountToken": "89.704738",
"amountInUsd": "89.73",
"tokenSymbol": "USDC",
"tokenIconUrl": "https://icons.llama.fi/usd-coin.jpg",
"isSwap": false
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 142,
"totalPages": 8,
"hasNext": true,
"hasPrevious": false
}
}
```
## Response Fields
Array of deposit activity items.
Unique identifier for the interaction record.
The opportunity the deposit was made into.
Interaction type. Always `deposit` for this endpoint.
On-chain transaction hash.
Chain ID where the transaction was executed.
UTC timestamp of the block containing the transaction (ISO 8601).
The depositor's wallet address.
Deposit amount in token units (human-readable). May be absent if token metadata is unavailable.
Deposit amount in USD. May be absent if price data is unavailable.
Symbol of the deposited token (e.g., `USDC`). May be absent if token metadata is unavailable.
URL to the token's icon. May be absent.
Whether the deposit used swap mode.
Pagination metadata.
Current page number.
Results per page.
Total number of matching deposits.
Total number of pages.
Whether a next page exists.
Whether a previous page exists.
## Filter by product
Retrieve deposits scoped to a specific product and its associated opportunities.
```typescript theme={null}
const response = await fetch(
`https://earn.turtle.xyz/v2/deposit/${distributorId}?productId=${productId}&page=1&limit=50`,
{ headers: { 'X-API-Key': 'pk_live_xxxxx' } }
);
const { deposits, pagination } = await response.json();
```
## Paginate through all deposits
```typescript theme={null}
const getAllDeposits = async (distributorId: string) => {
const all = [];
let page = 1;
while (true) {
const response = await fetch(
`https://earn.turtle.xyz/v2/deposit/${distributorId}?page=${page}&limit=100`,
{ headers: { 'X-API-Key': 'pk_live_xxxxx' } }
);
const { deposits, pagination } = await response.json();
all.push(...deposits);
if (!pagination.hasNext) break;
page++;
}
return all;
};
```
## Error Handling
**Status Code:** 404 Not Found
```json theme={null}
{
"error": {
"status": "NOT_FOUND",
"error": "distributor not found"
}
}
```
**Solution:** Verify your distributor ID is correct and active.
**Status Code:** 400 Bad Request
```json theme={null}
{
"error": {
"status": "INVALID_ARGUMENT",
"error": "invalid opportunityId: not-a-uuid"
}
}
```
**Solution:** Both `opportunityId` and `productId` must be valid UUIDs.
# Async Deposits
Source: https://docs.turtle.xyz/sdk/earn/async-deposits
When a deposit queues instead of settling, claim it to finalize or cancel it to recover funds
Action endpoints require the user to be a registered [Turtle member](/sdk/authentication/register-wallet).
Some vaults do not settle a deposit in one transaction. They queue it, process it on their own schedule, and only then is the position active. For those vaults the user has a follow-up decision once funds are pending: claim to finalize, or cancel to take the funds back. Both branches start from the same pending state and live on this page.
This applies only to opportunities with `complex` settlement (for example Mellow and Lagoon). Standard instant vaults never reach a pending state. See [Deposit modes](/sdk/concepts/deposit-modes) for how to detect which kind you are dealing with.
## Overview
`POST /v2/actions/claim-deposit/{opportunityId}`
`POST /v2/actions/cancel-deposit/{opportunityId}`
A pending deposit resolves exactly once. After the vault processes the queued funds, call claim-deposit to finalize the position; before processing completes, call cancel-deposit to return the funds to the user. Both endpoints take the same path parameter and body, and each returns an `actionId` and an ordered `transactions` array to sign and submit.
## The pending-deposit state machine
| State | How it got here | What you can do |
| --------- | ---------------------------------------------------------------------- | -------------------------------------------------------------- |
| Pending | User deposited into a `complex` vault; the vault has queued the funds. | Wait for the vault to process, or cancel to recover funds now. |
| Processed | The vault finished processing the queued deposit. | Claim to finalize the position. |
| Claimed | The user claimed the processed deposit. | Done. The position is active. |
| Cancelled | The user cancelled before processing completed. | Done. Funds returned to the user. |
Claim and cancel are mutually exclusive resolutions of the same pending deposit. Both endpoints take only the user's address and your distributor ID, because the vault already holds the pending-deposit details keyed to that wallet.
## Detect a pending deposit
A deposit is pending only when the opportunity is `complex`. Read the deposit-steps type off the opportunity object before assuming a claim is needed.
## Claim to finalize
Once the vault has processed the queued deposit, generate the claim transaction to finalize the position.
`POST /v2/actions/claim-deposit/{opportunityId}`
```bash curl theme={null}
curl -X POST "https://earn.turtle.xyz/v2/actions/claim-deposit/{opportunityId}" \
-H "Content-Type: application/json" \
-d '{
"userAddress": "0x1234...",
"distributorId": "your-distributor-id"
}'
```
```typescript TypeScript theme={null}
const opportunityId = '550e8400-e29b-41d4-a716-446655440000';
const response = await fetch(
`https://earn.turtle.xyz/v2/actions/claim-deposit/${opportunityId}`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
userAddress: '0x1234...',
distributorId: 'your-distributor-id',
}),
}
);
const data = await response.json();
```
## Response Example
```json theme={null}
{
"actionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"transactions": [
{
"type": "claimDeposit",
"transaction": {
"to": "0x...",
"data": "0x...",
"value": "0",
"gasLimit": "200000",
"chainId": 1
},
"description": "Claim pending deposit"
}
]
}
```
## Cancel to abort
If the user would rather recover funds than wait for the vault to process the deposit, generate the cancel transaction. Funds are returned to the user.
`POST /v2/actions/cancel-deposit/{opportunityId}`
```bash curl theme={null}
curl -X POST "https://earn.turtle.xyz/v2/actions/cancel-deposit/{opportunityId}" \
-H "Content-Type: application/json" \
-d '{
"userAddress": "0x1234...",
"distributorId": "your-distributor-id"
}'
```
```typescript TypeScript theme={null}
const opportunityId = '550e8400-e29b-41d4-a716-446655440000';
const response = await fetch(
`https://earn.turtle.xyz/v2/actions/cancel-deposit/${opportunityId}`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
userAddress: '0x1234...',
distributorId: 'your-distributor-id',
}),
}
);
const data = await response.json();
```
## Response Example
```json theme={null}
{
"actionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"transactions": [
{
"type": "cancelDeposit",
"transaction": {
"to": "0x...",
"data": "0x...",
"value": "0",
"gasLimit": "200000",
"chainId": 1
},
"description": "Cancel pending deposit"
}
]
}
```
## Shared parameters
Both endpoints take the same path parameter and body.
**Path Parameters**
The opportunity holding the pending deposit. Get it from [Get Opportunities](/sdk/opportunities/get-opportunities).
**Body Parameters**
The user's EVM wallet address. Must belong to a registered Turtle member with a pending deposit in this opportunity.
Your distributor ID for attribution tracking.
## Response Fields
Both endpoints return the same shape.
Unique identifier for this action, returned for both claim and cancel.
Ordered array of transactions to sign and submit. Each element follows the [Transaction Object](#transaction-object) shape rendered below; claim returns a single `claimDeposit` transaction and cancel returns a single `cancelDeposit` transaction.
## Broadcast
Each endpoint returns a single transaction. Sign and submit it.
```typescript theme={null}
const { transactions } = await response.json();
const tx = transactions[0];
const txResponse = await wallet.sendTransaction(tx.transaction);
await txResponse.wait();
```
### Transaction Object
Each transaction in the `transactions` array contains:
Transaction type, e.g. `approve`, `deposit`, `withdraw`, `claimDeposit`, `cancelDeposit`.
The raw transaction data to sign and submit.
Target contract address.
Encoded calldata (hex string with `0x` prefix).
Value in wei. Usually `"0"` for token interactions; non-zero for native token deposits.
Estimated gas limit.
Chain ID for the transaction.
Human-readable description of what this transaction does.
Optional metadata for swap transactions, including provider info, amount out, gas estimate, and route details.
## Operational Notes
Claim and cancel apply only to opportunities with `complex` settlement. Instant vaults complete on deposit and have nothing to claim or cancel.
Neither endpoint takes a token or amount. The vault already holds the pending-deposit details keyed to the user's address, so the request only needs `userAddress` and `distributorId`.
A pending deposit resolves once, either to claimed or cancelled. After the vault processes the deposit, claim finalizes it; before processing completes, cancel returns the funds.
## Error Handling
**Status:** 403 Forbidden
```json theme={null}
{
"error": "not_a_member",
"message": "User is not a Turtle member. Please complete the membership flow first.",
"docsUrl": "https://docs.turtle.xyz/sdk/authentication/register-wallet"
}
```
**Solution:** Complete the [membership flow](/sdk/authentication/register-wallet) first.
**Status:** 404 Not Found
```json theme={null}
{
"error": "distributor_not_found",
"message": "Distributor not found with the provided ID"
}
```
**Solution:** Verify your distributor ID is correct and active.
**Status:** 404 Not Found
```json theme={null}
{
"error": "opportunity_not_found",
"message": "Opportunity not found"
}
```
**Solution:** Check the opportunity ID with [Get Opportunities](/sdk/opportunities/get-opportunities).
# Deposit
Source: https://docs.turtle.xyz/sdk/earn/deposit
Build a ready-to-sign deposit into an opportunity, including the swap-mode variant, and broadcast it
Requires an API key via the `X-API-Key` header. See [API Keys](/sdk/authentication/api-keys).
The user must be a registered [Turtle member](/sdk/authentication/register-wallet) before you can deposit on their behalf. A non-member request fails (see Error Handling).
Depositing is three moves: build the deposit, have the user broadcast the returned transactions in order, then attribution lands on its own. Direct and swap deposits use the same endpoint and differ only by the `mode` field. For the concept behind direct vs swap and instant vs async, see [Deposit modes](/sdk/concepts/deposit-modes).
## Overview
`POST /v2/actions/deposit/{opportunityId}`
The endpoint returns an `actionId` and an ordered `transactions` array. The user signs and submits each transaction in sequence (for an ERC-20 deposit, typically an `approve` followed by a `deposit`).
## Build the deposit
Pass the user's address, the input token, the amount in the token's smallest unit, and your `distributorId`. Use `mode: "direct"` to deposit the vault's native token.
```bash curl theme={null}
curl -X POST "https://earn.turtle.xyz/v2/actions/deposit/{opportunityId}" \
-H "X-API-Key: pk_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"userAddress": "0x1234...",
"tokenIn": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"amount": "1000000",
"distributorId": "your-distributor-id",
"mode": "direct",
"slippageBps": 50
}'
```
```typescript TypeScript theme={null}
const opportunityId = '550e8400-e29b-41d4-a716-446655440000';
const response = await fetch(
`https://earn.turtle.xyz/v2/actions/deposit/${opportunityId}`,
{
method: 'POST',
headers: { 'X-API-Key': 'pk_live_xxxxx', 'Content-Type': 'application/json' },
body: JSON.stringify({
userAddress: '0x1234...',
tokenIn: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
amount: '1000000', // 1 USDC (6 decimals)
distributorId: 'your-distributor-id',
mode: 'direct',
slippageBps: 50,
}),
}
);
const data = await response.json();
```
**Path Parameters**
The opportunity to deposit into. Get it from [Get Opportunities](/sdk/opportunities/get-opportunities). IDs are UUIDs.
**Body Parameters**
The user's EVM wallet address. Must belong to a registered Turtle member.
Address of the token being deposited. Must be supported on the opportunity's chain. Cannot be the vault's receipt token.
Deposit amount in the token's smallest unit (wei). Must be greater than 0.
Your distributor ID. Embedded into the deposit calldata for [automatic attribution](/sdk/concepts/distributor-model).
`direct` deposits the vault's native token. `swap` routes a different input token through a DEX first. See the swap-mode section below.
Maximum acceptable slippage in basis points, applied in `swap` mode. `50` = 0.5%.
Optional referral code for deposit attribution.
**Response**
```json theme={null}
{
"actionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"transactions": [
{
"type": "approve",
"transaction": {
"to": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"data": "0x095ea7b3000000000000000000000000...",
"value": "0",
"gasLimit": "60000",
"chainId": 1
},
"description": "Approve USDC spending"
},
{
"type": "deposit",
"transaction": {
"to": "0x...",
"data": "0x...",
"value": "0",
"gasLimit": "250000",
"chainId": 1
},
"description": "Deposit USDC into vault"
}
]
}
```
### Transaction Object
Each transaction in the `transactions` array contains:
Transaction type, e.g. `approve`, `deposit`, `withdraw`, `claimDeposit`, `cancelDeposit`.
The raw transaction data to sign and submit.
Target contract address.
Encoded calldata (hex string with `0x` prefix).
Value in wei. Usually `"0"` for token interactions; non-zero for native token deposits.
Estimated gas limit.
Chain ID for the transaction.
Human-readable description of what this transaction does.
Optional metadata for swap transactions, including provider info, amount out, gas estimate, and route details.
## Swap mode
When the user wants to deposit a token that is not the vault's native deposit token, set `mode` to `swap` and pass that token as `tokenIn`. The API routes the swap through a DEX before depositing. Swap mode is available when `swapRouteEnabled` is `true` on the opportunity. See [Deposit modes](/sdk/concepts/deposit-modes) for the full availability matrix.
```bash curl theme={null}
curl -X POST "https://earn.turtle.xyz/v2/actions/deposit/{opportunityId}" \
-H "X-API-Key: pk_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"userAddress": "0x1234...",
"tokenIn": "0xInputTokenAddress",
"amount": "1000000",
"distributorId": "your-distributor-id",
"mode": "swap",
"slippageBps": 100
}'
```
```typescript TypeScript theme={null}
const opportunityId = '550e8400-e29b-41d4-a716-446655440000';
const response = await fetch(
`https://earn.turtle.xyz/v2/actions/deposit/${opportunityId}`,
{
method: 'POST',
headers: { 'X-API-Key': 'pk_live_xxxxx', 'Content-Type': 'application/json' },
body: JSON.stringify({
userAddress: '0x1234...',
tokenIn: '0xInputTokenAddress',
amount: '1000000',
distributorId: 'your-distributor-id',
mode: 'swap',
slippageBps: 100,
}),
}
);
const action = await response.json();
```
The swap-mode response carries swap details in each transaction's `metadata` (provider, amount out, route). The rest of the broadcast flow is identical.
## Broadcast
Sign and submit each transaction in the returned order. Wait for each to confirm before sending the next, since a later transaction often depends on an earlier one (a `deposit` cannot land before its `approve`).
```typescript theme={null}
// 1. Build the deposit action
const depositResponse = await fetch(
`https://earn.turtle.xyz/v2/actions/deposit/${opportunityId}`,
{
method: 'POST',
headers: { 'X-API-Key': 'pk_live_xxxxx', 'Content-Type': 'application/json' },
body: JSON.stringify({
userAddress: walletAddress,
tokenIn: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
amount: '1000000000', // 1000 USDC
distributorId: 'your-distributor-id',
mode: 'direct',
}),
}
);
const { actionId, transactions } = await depositResponse.json();
// 2. Sign and submit each transaction in order
for (const tx of transactions) {
const txResponse = await wallet.sendTransaction(tx.transaction);
await txResponse.wait(); // wait for on-chain confirmation before the next
}
// 3. Attribution is automatic. Turtle detects the tracking signature in
// the deposit calldata and attributes it to your distributor.
```
## Verify the deposit
Attribution is automatic, so there is nothing to call to record it. If you want to confirm a specific deposit carried your tracking data, pass its transaction hash to the verify endpoint. That step has its own page: [Verify Attribution](/sdk/earn/verify-attribution).
If the opportunity is async (`complex` settlement), the deposit will sit pending until you claim it. Handle that on [Async Deposits](/sdk/earn/async-deposits).
## Operational Notes
`amount` is in wei for the input token's decimals. 1 USDC (6 decimals) is `"1000000"`; 1 DAI (18 decimals) is `"1000000000000000000"`. Pass the raw integer string. Never send a human-readable decimal.
The `transactions` array is ordered. An ERC-20 deposit returns an `approve` then a `deposit`. Confirm each before broadcasting the next.
`mode: "swap"` only works when the opportunity has `swapRouteEnabled: true`. Read availability off the opportunity object. See [Deposit modes](/sdk/concepts/deposit-modes).
For opportunities with `complex` settlement (for example Mellow, Lagoon), the deposit queues and is not active until claimed. See [Async Deposits](/sdk/earn/async-deposits).
The user must be a registered Turtle member. Complete the [membership flow](/sdk/authentication/register-wallet) first.
## Error Handling
**Status:** 403 Forbidden
```json theme={null}
{
"error": "not_a_member",
"message": "User is not a Turtle member. Please complete the membership flow first.",
"docsUrl": "https://docs.turtle.xyz/sdk/authentication/register-wallet"
}
```
**Solution:** Complete the [membership flow](/sdk/authentication/register-wallet) before depositing.
**Status:** 404 Not Found
```json theme={null}
{
"error": "distributor_not_found",
"message": "Distributor not found with the provided ID"
}
```
**Solution:** Verify your distributor ID is correct and active.
**Status:** 404 Not Found
```json theme={null}
{
"error": "opportunity_not_found",
"message": "Opportunity not found"
}
```
**Solution:** Check the opportunity ID with [Get Opportunities](/sdk/opportunities/get-opportunities).
**Status:** 400 Bad Request
```json theme={null}
{
"error": "deposits_disabled",
"message": "Deposits are disabled for this opportunity"
}
```
**Solution:** Deposits are temporarily disabled for this opportunity. Try a different one.
**Status:** 400 Bad Request
```json theme={null}
{
"error": "invalid_token",
"message": "Token 0x... not supported for chain 1"
}
```
**Solution:** Use a supported deposit token. Check the opportunity's `depositTokens` array.
**Status:** 400 Bad Request
```json theme={null}
{
"code": 400,
"status": "INVALID_ARGUMENT",
"error": "insufficient token balance"
}
```
The API reads the user's on-chain balance of `tokenIn` before building the transactions and rejects the request when the wallet holds less than `amount`. Native-token deposits are checked against the wallet's native balance.
**Solution:** Reduce `amount` to at most the wallet's balance of `tokenIn`, or top the wallet up before retrying.
# Earn API quickstart
Source: https://docs.turtle.xyz/sdk/earn/quickstart
Go from zero to your first attributed deposit with the Turtle Earn API.
This is the shortest path from nothing to a deposit attributed to your distributor: authenticate, register the user's wallet, find an opportunity, generate the deposit, and confirm attribution. Each step links to the full reference where the request bodies and response schemas live.
New to the Turtle API? Start with the [API overview](/sdk/overview) for access and the full product set. This page covers the Earn deposit flow specifically.
Every call requires the `X-API-Key` header. See [API Keys](/sdk/authentication/api-keys).
## Prerequisites
You need three things before the first call:
1. A Turtle organization, created in the [Client Portal](https://dashboard.turtle.xyz). New organizations are approved by the Turtle team before keys are issued.
2. An **API key** (`pk_live_` for client-side, `sk_live_` for server-side). See [API Keys](/sdk/authentication/api-keys).
3. Your **distributor ID**, found under Distribution in the [Client Portal](https://dashboard.turtle.xyz).
If your organization has not been approved yet, reach out on [Discord](https://discord.turtle.xyz).
## Step 1: Confirm your key works
Fetch the opportunity catalog. A `200` with a `data` array means authentication is set up.
```bash curl theme={null}
curl https://earn.turtle.xyz/v2/opportunities/ \
-H "X-API-Key: pk_live_xxxxx"
```
```typescript TypeScript theme={null}
const res = await fetch('https://earn.turtle.xyz/v2/opportunities/', {
headers: { 'X-API-Key': 'pk_live_xxxxx' },
});
const { data, pagination } = await res.json();
```
A `401` means the key is missing or wrong. See [API Keys](/sdk/authentication/api-keys) for key types, the auth header, and rate limits.
## Step 2: Register the user's wallet
Every wallet must be a Turtle member before it can deposit. Membership is a three-step EIP-4361 flow: check membership, request a sign-in message, submit the signature. The full request and response for each step is on [Register Wallet](/sdk/authentication/register-wallet).
```bash curl theme={null}
# 1. Already a member?
curl "https://earn.turtle.xyz/v2/membership/?address=0xYOUR_WALLET&walletEcosystem=evm" \
-H "X-API-Key: pk_live_xxxxx"
# 2. If not, request a message, have the user sign it, and submit the signature.
# See Register Wallet for the agreement and create-membership request bodies.
```
```typescript TypeScript theme={null}
// 1. Already a member?
const { isMember } = await (
await fetch(
`https://earn.turtle.xyz/v2/membership/?address=${address}&walletEcosystem=evm`,
{ headers: { 'X-API-Key': 'pk_live_xxxxx' } }
)
).json();
// 2. If not, request a message, have the user sign it, and submit the signature.
// See Register Wallet for the agreement and create-membership request bodies.
```
Pass your `distributorId` when you create the membership to attribute the signup to your integration.
## Step 3: Find an opportunity
Fetch your distributor's configured set, or browse the full catalog with filters. Each opportunity has an `id` you use in the next step.
```bash curl theme={null}
curl "https://earn.turtle.xyz/v2/opportunities/distributors/YOUR_DISTRIBUTOR_ID" \
-H "X-API-Key: pk_live_xxxxx"
```
```typescript TypeScript theme={null}
const { data } = await (
await fetch(
`https://earn.turtle.xyz/v2/opportunities/distributors/${distributorId}`,
{ headers: { 'X-API-Key': 'pk_live_xxxxx' } }
)
).json();
const opportunity = data[0];
```
See [Opportunities](/sdk/opportunities/get-opportunities) for the full object reference, filters, and the distributor-scoped variant.
## Step 4: Generate the deposit
Call the deposit action with the opportunity ID, wallet, token, amount, and your distributor ID. The API returns an ordered `transactions` array (typically an approval followed by the deposit) for the user to sign in order.
```bash curl theme={null}
curl -X POST "https://earn.turtle.xyz/v2/actions/deposit/OPPORTUNITY_ID" \
-H "X-API-Key: pk_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"userAddress": "0xYOUR_WALLET",
"tokenIn": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"amount": "1000000",
"distributorId": "YOUR_DISTRIBUTOR_ID"
}'
```
```typescript TypeScript theme={null}
const { transactions } = await (
await fetch(`https://earn.turtle.xyz/v2/actions/deposit/${opportunity.id}`, {
method: 'POST',
headers: { 'X-API-Key': 'pk_live_xxxxx', 'Content-Type': 'application/json' },
body: JSON.stringify({
userAddress: address,
tokenIn: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
amount: '1000000', // base units (1 USDC, 6 decimals)
distributorId: 'YOUR_DISTRIBUTOR_ID',
}),
})
).json();
for (const tx of transactions) {
const sent = await signer.sendTransaction(tx.transaction);
await sent.wait();
}
```
The wallet must be a member (Step 2) before this call.
For the full request body, swap mode, async (pending) deposits, and the broadcast loop, see [Deposit](/sdk/earn/deposit).
## Step 5: Confirm attribution
After the deposit confirms on-chain, verify that Turtle attributed it to you.
```bash curl theme={null}
curl "https://earn.turtle.xyz/v2/actions/verify?chainId=1&txHash=0xYOUR_TX_HASH" \
-H "X-API-Key: pk_live_xxxxx"
```
```typescript TypeScript theme={null}
const { metadata, signatureValid } = await (
await fetch(
`https://earn.turtle.xyz/v2/actions/verify?chainId=1&txHash=${txHash}`,
{ headers: { 'X-API-Key': 'pk_live_xxxxx' } }
)
).json();
```
A `metadata.distributorId` matching yours and `signatureValid: true` means attribution worked. Nothing else is required; attribution is automatic. See [Verify Attribution](/sdk/earn/verify-attribution).
## What's next
* **[Deposit](/sdk/earn/deposit)** - The full deposit reference: request body, swap mode, and broadcasting.
* **[Opportunities](/sdk/opportunities/get-opportunities)** - The opportunity catalog and the full object schema.
* **[Verify Attribution](/sdk/earn/verify-attribution)** - Confirm a transaction was attributed to your distributor.
* **[Distributor Model](/sdk/concepts/distributor-model)** - How attribution and revenue share work end to end.
# Verify Attribution
Source: https://docs.turtle.xyz/sdk/earn/verify-attribution
Confirm that a transaction carries valid Turtle tracking data for your distributor
Requires an API key via the `X-API-Key` header. See [API Keys](/sdk/authentication/api-keys).
## Overview
`GET /v2/actions/verify`
Check whether a transaction carries valid Turtle tracking data. Pass a transaction hash and chain ID, and the endpoint returns the tracking tag, the parsed attribution `metadata` (including `distributorId`, `opportunityId`, the deposited `amount`, and `referralCode`), and whether the signature is from Turtle's attribution wallet. Use it to confirm attribution independently, or for debugging.
This works for any attributed deposit, however it was generated. A deposit built through [Deposit](/sdk/earn/deposit) and a no-code [share-link](/partner-products/share-links) deposit both embed the same tracking signature, so both verify the same way.
```bash curl theme={null}
curl -X GET "https://earn.turtle.xyz/v2/actions/verify?chainId=1&txHash=0xedfdf71e..." \
-H "X-API-Key: pk_live_xxxxx"
```
```typescript TypeScript theme={null}
const params = new URLSearchParams({
chainId: '1',
txHash: '0xedfdf71e0e4daec5afcb87988821a8bccd5c282647c8e81a65a71181a44a8e51',
});
const response = await fetch(
`https://earn.turtle.xyz/v2/actions/verify?${params}`,
{ headers: { 'X-API-Key': 'pk_live_xxxxx' } }
);
const data = await response.json();
```
**Query Parameters**
The chain ID where the transaction was executed (e.g., `1` for Ethereum, `42161` for Arbitrum).
The transaction hash to verify (`0x` followed by 64 hex characters).
**Response**
```json theme={null}
{
"tag": "turtle:v1:dist123:ref456",
"metadata": {
"action": "deposit",
"actionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"amount": "1000000",
"amountUsd": "1.00",
"distributorId": "dist123",
"opportunityId": "550e8400-e29b-41d4-a716-446655440000",
"referralCode": "ref456",
"tokenIn": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"tokenInDecimals": 6
},
"signatureValid": true
}
```
The raw tracking tag found in the transaction data.
Parsed attribution metadata for the transaction.
The attributed action type (e.g., `deposit`).
The action ID associated with the attributed transaction.
The deposited amount in the input token's smallest unit.
The deposited amount in USD.
The distributor the transaction is attributed to.
The opportunity the deposit was made into.
The referral code embedded in the tracking data, if present.
The address of the input token.
The decimals of the input token.
Whether the tracking signature is from Turtle's attribution wallet.
Error message if verification failed (e.g., no tracking data found).
## Error Handling
**Status:** 400 Bad Request
```json theme={null}
{
"error": "invalid_request",
"message": "Invalid txHash or chainId"
}
```
**Solution:** Pass a `chainId` integer for a supported chain and a `txHash` of `0x` followed by 64 hex characters.
**Status:** 404 Not Found
```json theme={null}
{
"error": "tracking_data_not_found",
"message": "No tracking data found in transaction"
}
```
**Solution:** Confirm the transaction is the attributed deposit and that it embedded a Turtle tracking signature. A plain transfer or a deposit built without a `distributorId` carries no tracking data.
**Status:** 200 OK
```json theme={null}
{
"tag": "turtle:v1:dist123:ref456",
"metadata": {
"action": "deposit",
"actionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"amount": "1000000",
"amountUsd": "1.00",
"distributorId": "dist123",
"opportunityId": "550e8400-e29b-41d4-a716-446655440000",
"referralCode": "ref456",
"tokenIn": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"tokenInDecimals": 6
},
"signatureValid": false
}
```
**Solution:** A tracking tag is present but its signature is not from Turtle's attribution wallet, so the deposit is not attributed. Rebuild the deposit through [Deposit](/sdk/earn/deposit) so the tracking signature is generated by Turtle.
## Related
* [Deposit](/sdk/earn/deposit): Generate the deposit whose attribution you are verifying
* [Distributor Activity](/sdk/earn-api/deposits): List every deposit attributed to your distributor
* [Distributor Model](/sdk/concepts/distributor-model): How attribution and revenue tracking work
# Withdraw
Source: https://docs.turtle.xyz/sdk/earn/withdraw
Generate ready-to-sign transactions for withdrawing from an opportunity
Requires an API key via the `X-API-Key` header. See [API Keys](/sdk/authentication/api-keys).
## Overview
`POST /v2/actions/withdraw/{opportunityId}`
The withdraw endpoint generates transactions to redeem shares from a vault/opportunity. The typical flow is:
Call the endpoint to generate the transactions.
The user signs and submits each transaction in order (e.g., approve + withdraw). No further action needed.
All action endpoints require the user to be a [Turtle member](/sdk/authentication/register-wallet). Make sure the user has completed the membership flow before calling these endpoints.
## Create Withdraw
Generate the transactions needed to withdraw from an opportunity. The response contains an ordered list of transactions the user must sign and submit (e.g., approve + withdraw).
```bash curl theme={null}
curl -X POST "https://earn.turtle.xyz/v2/actions/withdraw/{opportunityId}" \
-H "X-API-Key: pk_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"userAddress": "0x1234...",
"amount": "1000000000000000000",
"distributorId": "your-distributor-id",
"tokenOut": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"slippageBps": 50
}'
```
```typescript TypeScript theme={null}
const opportunityId = '550e8400-e29b-41d4-a716-446655440000';
const response = await fetch(
`https://earn.turtle.xyz/v2/actions/withdraw/${opportunityId}`,
{
method: 'POST',
headers: { 'X-API-Key': 'pk_live_xxxxx', 'Content-Type': 'application/json' },
body: JSON.stringify({
userAddress: '0x1234...',
amount: '1000000000000000000', // shares to redeem in smallest unit
distributorId: 'your-distributor-id',
tokenOut: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
slippageBps: 50,
}),
}
);
const data = await response.json();
```
**Path Parameters**
The unique identifier of the opportunity to withdraw from. Get this from the [Opportunities API](/sdk/opportunities/get-opportunities).
**Body Parameters**
The user's EVM wallet address. Must belong to a registered Turtle member.
The number of shares to redeem in the smallest unit. Must be greater than 0.
Your distributor ID for attribution tracking.
The address of the token to receive after withdrawal. Required for some providers (e.g., Midas, Mellow, Veda). If not provided, the vault's default withdraw token is used.
Slippage tolerance in basis points. For example, `50` = 0.5% slippage. Only applied to opportunities that require it.
**Response**
```json theme={null}
{
"actionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"transactions": [
{
"type": "approve",
"transaction": {
"to": "0x...",
"data": "0x095ea7b3000000000000000000000000...",
"value": "0",
"gasLimit": "60000",
"chainId": 1
},
"description": "Approve shares spending"
},
{
"type": "withdraw",
"transaction": {
"to": "0x...",
"data": "0x...",
"value": "0",
"gasLimit": "300000",
"chainId": 1
},
"description": "Withdraw from vault"
}
]
}
```
### Transaction Object
Each transaction in the `transactions` array contains:
Transaction type, e.g. `approve`, `deposit`, `withdraw`, `claimDeposit`, `cancelDeposit`.
The raw transaction data to sign and submit.
Target contract address.
Encoded calldata (hex string with `0x` prefix).
Value in wei. Usually `"0"` for token interactions; non-zero for native token deposits.
Estimated gas limit.
Chain ID for the transaction.
Human-readable description of what this transaction does.
Optional metadata for swap transactions, including provider info, amount out, gas estimate, and route details.
## Complete Example
Here's a full withdraw flow from start to finish:
```typescript theme={null}
const opportunityId = '550e8400-e29b-41d4-a716-446655440000';
const walletAddress = '0x1234...';
// 1. Create the withdraw action
const withdrawResponse = await fetch(
`https://earn.turtle.xyz/v2/actions/withdraw/${opportunityId}`,
{
method: 'POST',
headers: { 'X-API-Key': 'pk_live_xxxxx', 'Content-Type': 'application/json' },
body: JSON.stringify({
userAddress: walletAddress,
amount: '1000000000000000000', // shares to redeem
distributorId: 'your-distributor-id',
tokenOut: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // receive USDC
}),
}
);
const { transactions } = await withdrawResponse.json();
// 2. Sign and submit each transaction in order
for (const tx of transactions) {
const txResponse = await wallet.sendTransaction(tx.transaction);
await txResponse.wait(); // Wait for confirmation
}
```
## Operational Notes
`amount` is the number of vault shares to redeem, expressed in the share token's smallest unit. Pass the raw integer string. Never send a human-readable decimal.
The `transactions` array is ordered. A withdrawal typically returns an `approve` then a `withdraw`. Confirm each before broadcasting the next.
`tokenOut` sets the token the user receives. It is required for some providers (e.g., Midas, Mellow, Veda). If not provided, the vault's default withdraw token is used.
`slippageBps` is the slippage tolerance in basis points (`50` = 0.5%). It is only applied to opportunities that require it.
The user must be a registered Turtle member. Complete the [membership flow](/sdk/authentication/register-wallet) first.
## Error Handling
**Status Code:** 403 Forbidden
```json theme={null}
{
"error": "not_a_member",
"message": "User is not a Turtle member. Please complete the membership flow first.",
"docsUrl": "https://docs.turtle.xyz/sdk/authentication/register-wallet"
}
```
**Solution:** Complete the [membership flow](/sdk/authentication/register-wallet) before calling action endpoints.
**Status Code:** 404 Not Found
```json theme={null}
{
"error": "distributor_not_found",
"message": "Distributor not found with the provided ID"
}
```
**Solution:** Verify your distributor ID is correct and active.
**Status Code:** 404 Not Found
```json theme={null}
{
"error": "opportunity_not_found",
"message": "Opportunity not found"
}
```
**Solution:** Check the opportunity ID using the [Opportunities API](/sdk/opportunities/get-opportunities).
**Status Code:** 400 Bad Request
```json theme={null}
{
"error": "INVALID_ARGUMENT",
"message": "invalid tokenOut address format"
}
```
**Solution:** Provide a valid EVM address for the `tokenOut` field.
**Status Code:** 400 Bad Request
```json theme={null}
{
"code": 400,
"status": "INVALID_ARGUMENT",
"error": "insufficient token balance"
}
```
The API reads the user's on-chain share balance before building the withdraw transactions and rejects the request when the wallet holds fewer shares than `amount`.
**Solution:** Lower `amount` to at most the wallet's current share balance for the opportunity.
## Related Endpoints
* [Deposit](/sdk/earn/deposit) - Generate deposit transactions
* [Get Opportunities](/sdk/opportunities/get-opportunities) - Discover available opportunities and their IDs
# Opportunities
Source: https://docs.turtle.xyz/sdk/opportunities/get-opportunities
Discover and query the vaults, money markets, and earning opportunities available on Turtle.
All requests require an API key via the `X-API-Key` header.
See [API Keys](/sdk/authentication/api-keys) for details.
## Overview
The Opportunities API is how you discover what a user can deposit into. Each opportunity carries its accepted tokens, chain, estimated APR, current TVL, incentives, and which deposit modes it supports. This page is the canonical reference for the Opportunity object; every other endpoint that returns one links here.
There are three read endpoints:
* `GET /v2/opportunities/` lists the full catalog, with optional filters.
* `GET /v2/opportunities/{id}` returns one opportunity by ID.
* `GET /v2/opportunities/distributors/{distributorId}` returns the set configured for a distributor.
For the product context (what configuration is and why you'd scope a set), see the [Distribution overview](/partner-products/distribution/overview).
## Get All Opportunities
Retrieve all available opportunities with simplified token information.
```bash curl theme={null}
curl -X GET "https://earn.turtle.xyz/v2/opportunities/" \
-H "X-API-Key: pk_live_xxxxx"
```
```typescript TypeScript theme={null}
interface OpportunityResponse {
data: Opportunity[];
pagination: {
page: number;
limit: number;
total: number;
totalPages: number;
};
}
const response = await fetch('https://earn.turtle.xyz/v2/opportunities/', {
headers: { 'X-API-Key': 'pk_live_xxxxx' },
});
const data: OpportunityResponse = await response.json();
```
**Query Parameters**
Comma-separated list of chain IDs to filter by. Example: `1,8453,42161` for Ethereum, Base, and Arbitrum.
Filter by deposit token in the format `address-chainId`. Example: `0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7-43114`.
Return only opportunities with TVL at or above this USD value. Example: `1000000` returns opportunities above \$1M.
Return only opportunities with TVL at or below this USD value.
**Response**
```json theme={null}
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "USDC Vault",
"slug": "usdc-vault",
"description": "Stable yield on USDC deposits",
"type": "vault",
"tvl": 5000000.50,
"estimatedApr": 8.5,
"featured": true,
"minDepositAmountUsd": 0.01,
"meta": {
"directInteractionEnabled": true,
"routedSwapEnabled": true,
"depositEnabled": true,
"withdrawEnabled": true,
"asyncDeposit": false,
"asyncWithdraw": false,
"isSecondaryMarket": false,
"depositDisabledReason": "",
"withdrawalDisabledReason": ""
},
"depositTokens": [
{
"symbol": "USDC",
"address": "0xA0b86991...",
"chainId": 1,
"decimals": 6,
"logoUrl": "https://..."
}
],
"baseToken": {
"symbol": "USDC",
"address": "0xA0b86991...",
"chainId": 1,
"decimals": 6,
"logoUrl": "https://..."
},
"receiptToken": {
"symbol": "tUSDC",
"address": "0x...",
"chainId": 1,
"decimals": 6,
"logoUrl": "https://..."
},
"curator": {
"id": "curator-uuid",
"name": "Curator Name",
"description": "Curator description",
"iconUrl": "https://...",
"landingUrl": "https://..."
},
"incentives": [
{
"id": "incentive-uuid",
"name": "Incentive Name",
"description": "Incentive description",
"iconUrl": "https://...",
"rewardType": "tokens",
"rewardTypeName": "Tokens",
"fdvEstimate": null,
"tokenSupplyAllocation": null,
"apr": 0.001,
"minApr": null,
"maxApr": null,
"estPriceUsd": null,
"indexed": false
}
]
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 12,
"totalPages": 1
}
}
```
## Get Opportunity by ID
Retrieve a single opportunity by its unique identifier.
```bash curl theme={null}
curl -X GET "https://earn.turtle.xyz/v2/opportunities/b91fab34-3998-468b-adcf-645d9b68bc9c" \
-H "X-API-Key: pk_live_xxxxx"
```
```typescript TypeScript theme={null}
const opportunityId = 'b91fab34-3998-468b-adcf-645d9b68bc9c';
const response = await fetch(`https://earn.turtle.xyz/v2/opportunities/${opportunityId}`, {
headers: { 'X-API-Key': 'pk_live_xxxxx' },
});
const opportunity = await response.json();
```
**Path Parameters**
Opportunity unique identifier.
**Response**
Returns a single Opportunity object directly, using the structure documented under [Response Fields](#response-fields).
## Get Distributor Opportunities
Every distributor has a set of opportunities configured in the [Client Portal](https://dashboard.turtle.xyz). This endpoint returns only that set: the opportunities your users should see. Use it instead of the full catalog when you want to serve exactly what you have selected for your integration.
```bash curl theme={null}
curl -X GET "https://earn.turtle.xyz/v2/opportunities/distributors/MpOgVDnc" \
-H "X-API-Key: pk_live_xxxxx"
```
```typescript TypeScript theme={null}
const distributorId = 'MpOgVDnc';
const response = await fetch(
`https://earn.turtle.xyz/v2/opportunities/distributors/${distributorId}`,
{ headers: { 'X-API-Key': 'pk_live_xxxxx' } }
);
const { data, pagination } = await response.json();
```
**Path Parameters**
Your distributor ID. Find it under Distribution in the [Client Portal](https://dashboard.turtle.xyz).
**Response**
Same shape as Get All Opportunities (a `data` array plus a `pagination` object), filtered to the configured set. An empty `data` array means no opportunities have been configured yet; that is a `200`, not an error.
**Which endpoint to use**
| Scenario | Endpoint |
| ------------------------------------------------------- | ----------------------------------------------- |
| Power your app with your configured opportunities | Get Distributor Opportunities |
| Browse the full Turtle catalog to decide what to enable | Get All Opportunities |
| Load a single opportunity for a detail page | [Get Opportunity by ID](#get-opportunity-by-id) |
How configuration works: select opportunities in the Client Portal, which stores them in the distributor's earn-details configuration, and this endpoint returns that selection. For the concept and how attribution ties to it, see [Distributor Model](/sdk/concepts/distributor-model).
## Response Fields
The same Opportunity object is returned by all three endpoints above.
### Opportunity Object
Opportunity unique identifier.
Opportunity display name.
URL-friendly identifier for the opportunity.
Opportunity detailed description.
Opportunity type, for example `vault` or `lending`.
Total Value Locked in USD.
Estimated annual percentage rate.
Whether the opportunity is featured.
Minimum deposit amount in USD. Deposits below this value are rejected.
Interaction and availability flags for the opportunity. See [Meta Object](#meta-object).
Tokens accepted for deposit.
Base token for the opportunity.
Token received as a receipt for deposits.
Curator organization for the opportunity.
Incentives available on this opportunity.
### Token Object
Token symbol, for example `USDC` or `ETH`.
Token contract address.
Numeric chain ID the token belongs to.
ERC20 decimals.
Token logo image URL.
### Meta Object
Whether direct interaction with the opportunity is available. When true, the user can deposit the vault's native token directly with `mode=direct`.
Whether entering via a routed swap is supported. When true, the user can deposit a different input token with `mode=swap` and the API routes through a DEX. See [Deposit Modes](/sdk/concepts/deposit-modes).
Whether deposits are currently enabled.
Whether withdrawals are currently enabled.
Whether deposits settle asynchronously and require a follow-up claim.
Whether withdrawals settle asynchronously.
Whether the opportunity can only be entered via a secondary market.
Reason deposits are disabled, if any.
Reason withdrawals are disabled, if any.
### Curator Object
Curator organization ID.
Curator name.
Curator description.
Curator icon image URL.
Curator website URL.
### Incentive Object
Incentive unique identifier.
Incentive name.
Incentive description.
Incentive icon URL.
Type of reward: `points`, `tokens`, `yield`, or `vesting`.
Human-readable reward type name.
Annual percentage rate. May be null.
Minimum annual percentage rate. May be null.
Maximum annual percentage rate. May be null.
Fully diluted valuation estimate. May be null.
Token supply allocation percentage. May be null.
Estimated price in USD. May be null.
Whether the incentive is indexed.
## Operational Notes
Some vaults settle deposits instantly; others (such as Mellow and Lagoon) are asynchronous and require a follow-up claim. In v2, the `meta.asyncDeposit` flag signals this: when `true`, the deposit settles asynchronously and the user must submit a follow-up claim. The `meta.asyncWithdraw` flag signals the same for withdrawals.
`GET /v2/opportunities/distributors/{distributorId}` returns `{ "data": [], "pagination": { "page": 1, "limit": 20, "total": 0, "totalPages": 0 } }` when nothing is configured. Treat this as a prompt to configure the set in the Client Portal, not as a failure.
## Error Handling
**Status Code:** 401 Unauthorized
**Solution:** Pass a valid `X-API-Key` header. See [API Keys](/sdk/authentication/api-keys).
**Status Code:** 404 Not Found
```json theme={null}
{
"code": 404,
"status": "NOT_FOUND",
"error": "distributor not found"
}
```
**Solution:** Verify the opportunity ID or distributor ID is correct and active.
**Status Code:** 500 Internal Server Error
**Solution:** Retry with exponential backoff and contact [support](https://discord.turtle.xyz) if it persists.
# Historical Data
Source: https://docs.turtle.xyz/sdk/opportunities/historical
Time-series APR, APY, share price, and TVL for an opportunity vault.
## Overview
Return a vault's historical metrics over time, bucketed at a configurable interval. Every endpoint is keyed by chain ID plus vault address and backed by Turtle's on-chain vault-metrics indexer.
There are four series, plus a combined endpoint:
* `GET /v2/opportunities/{chainId}/{vaultAddress}/historical/apr` for APR over time
* `GET /v2/opportunities/{chainId}/{vaultAddress}/historical/apy` for APY over time
* `GET /v2/opportunities/{chainId}/{vaultAddress}/historical/share-price` for share price over time
* `GET /v2/opportunities/{chainId}/{vaultAddress}/historical/tvl` for TVL over time
* `GET /v2/opportunities/{chainId}/{vaultAddress}/historical` for the combined series
Availability: the APR, APY, and share price series are live and returning data. Historical TVL (and the combined `/historical` endpoint, which includes it) is still coming online. These currently return an empty `data` array for most vaults while the TVL backfill completes.
## Shared parameters
All historical endpoints take the same path and query parameters.
**Path Parameters**
EVM chain ID (e.g. `1` for Ethereum, `8453` for Base).
0x-prefixed, 40-hex vault contract address.
**Query Parameters**
Inclusive lower bound of the range, RFC3339 / ISO-8601 (e.g. `2025-06-11T00:00:00Z`).
Inclusive upper bound of the range, RFC3339 / ISO-8601.
Point spacing (granularity) in **seconds**. Defaults to `86400` (1 day).
APY/APR trailing window (lookback) in **seconds**, independent of `step`. Defaults to `604800` (7 days). Applies to the `apr` and `apy` series.
## APR over time
```
GET /v2/opportunities/{chainId}/{vaultAddress}/historical/apr
```
```bash curl theme={null}
curl -X GET "https://earn.turtle.xyz/v2/opportunities/8453/0x25d9...832d/historical/apr?step=86400&startDate=2025-06-11T00:00:00Z&endDate=2026-06-11T00:00:00Z"
```
```typescript TypeScript theme={null}
const res = await fetch(
'https://earn.turtle.xyz/v2/opportunities/8453/0x25d9...832d/historical/apr?step=86400&startDate=2025-06-11T00:00:00Z&endDate=2026-06-11T00:00:00Z'
);
const { data } = await res.json();
```
**Response**
```json theme={null}
{
"data": [
{
"timestamp": "2026-06-10T23:49:35Z",
"blockNumber": 47173014,
"apr": { "base": 0.0824, "reward": 0, "total": 0.0824 }
}
]
}
```
Ordered list of APR buckets.
Bucket representative time, RFC3339 / ISO-8601.
On-chain block number of the snapshot chosen as the bucket representative.
APR for the bucket, expressed as a decimal (e.g. `0.0824` = 8.24%). `base` is the underlying yield, `reward` is incentive APR, and `total` is their sum.
## APY over time
```
GET /v2/opportunities/{chainId}/{vaultAddress}/historical/apy
```
Identical shape to APR, with an `apy` object (`base` / `reward` / `total`) in place of `apr`.
```json theme={null}
{
"data": [
{
"timestamp": "2026-06-10T23:49:35Z",
"blockNumber": 47173014,
"apy": { "base": 0.0858, "reward": 0, "total": 0.0858 }
}
]
}
```
## Share price over time
```
GET /v2/opportunities/{chainId}/{vaultAddress}/historical/share-price
```
```bash curl theme={null}
curl -X GET "https://earn.turtle.xyz/v2/opportunities/8453/0x25d9...832d/historical/share-price?step=86400&startDate=2025-06-11T00:00:00Z&endDate=2026-06-11T00:00:00Z"
```
```typescript TypeScript theme={null}
const res = await fetch(
'https://earn.turtle.xyz/v2/opportunities/8453/0x25d9...832d/historical/share-price?step=86400&startDate=2025-06-11T00:00:00Z&endDate=2026-06-11T00:00:00Z'
);
const { baseAsset, data } = await res.json();
```
**Response**
```json theme={null}
{
"baseAsset": {
"symbol": "USDT",
"address": "0xfde4c96c8593536e31f229ea8f37b2ada2699bb2",
"decimals": 6
},
"data": [
{
"timestamp": "2026-06-10T23:49:35Z",
"blockNumber": 47173014,
"sharePrice": { "native": 1.02403, "usd": 1.0231 }
}
]
}
```
The vault's underlying token. `null` when the vault has not been indexed yet, or its token is not registered.
Share price for the bucket. `native` is denominated in the base asset; `usd` is the USD value, or `null` when no USD price was available for that bucket.
## TVL over time
Historical TVL is coming online. The endpoint is live and accepts the shared parameters, but currently returns an empty `data` array (`{ "baseAsset": null, "data": [] }`) for most vaults while the TVL backfill completes.
```
GET /v2/opportunities/{chainId}/{vaultAddress}/historical/tvl
```
**Response** (shape once data is available)
```json theme={null}
{
"baseAsset": {
"symbol": "USDC",
"address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"decimals": 6
},
"data": [
{
"timestamp": "2026-06-10T23:49:35Z",
"blockNumber": 47173014,
"tvl": { "native": 1250000.0, "usd": 1250500.0 }
}
]
}
```
TVL for the bucket. `native` is denominated in the base asset; `usd` is the USD value, or `null` when no USD price was available for that bucket.
# Turtle API overview
Source: https://docs.turtle.xyz/sdk/overview
What the Turtle API does, how to get access, and the products you can build on.
The Turtle API is one REST API for distributing yield opportunities, running reward campaigns, and reading portfolio data. Most integrations start with Earn and attributed deposits, but the same keys and the same organization also give you Streams and portfolio data.
If you already have access and want to ship a deposit, go straight to the [Earn quickstart](/sdk/earn/quickstart).
## Get access
You need three things before your first call.
1. **An organization.** Create one in the [Client Portal](https://dashboard.turtle.xyz), or ask an existing org owner to add you to theirs. Turtle approves new organizations before any keys are issued.
2. **API keys.** Keys are issued with the organization. The publishable key (`pk_live_`) is safe in client-side code and covers reads; the secret key (`sk_live_`) is server-side only and required for writes such as generating deposits or managing streams. See [API Keys](/sdk/authentication/api-keys).
3. **A distributor ID.** Found under Distribution in the Client Portal. You pass it on Earn calls so deposits are attributed to your integration. See the [Distributor Model](/sdk/concepts/distributor-model).
## Products
* **[Turtle Earn](/sdk/earn/quickstart)** - Turn a vault interaction into ready-to-sign deposit and withdrawal transactions. Deposits are attributed to your distributor automatically, which is what drives revenue share.
* **[Streams](/sdk/streams/overview)** - Run points and token incentive campaigns against vault positions. The API handles snapshots, merkle trees, and on-chain claims.
* **[Portfolio & Activity](/sdk/portfolio/overview)** - Read what a wallet holds, what it has done, and which deposits flowed through your integration.
## Shared fundamentals
These apply across every product:
* **[API Keys](/sdk/authentication/api-keys)** - authenticate every request with the `X-API-Key` header, and read your rate-limit budget from the response headers.
* **[Register Wallet](/sdk/authentication/register-wallet)** - action endpoints require the user's wallet to be a registered Turtle member (EIP-4361).
* **[Distributor model](/sdk/concepts/distributor-model)** and **[deposit modes](/sdk/concepts/deposit-modes)** - the concepts behind attribution and settlement.
* **[Error codes](/sdk/reference/error-codes)** and the **[API explorer](/sdk/reference/api-explorer)** - the shared error set and a browsable reference for every endpoint.
# Wallet Activity
Source: https://docs.turtle.xyz/sdk/portfolio/activity
Query deposit and withdrawal history for any wallet address.
All requests require an API key via the `X-API-Key` header.
See [Authentication](/sdk/authentication/api-keys) for details.
## Overview
`GET /v2/wallets/activity/`
The Wallet Activity endpoint returns on-chain earn interactions (deposits and withdrawals) for one or more wallet addresses across all opportunities and distributors. Results are ordered by date descending.
This is a **wallet-scoped** endpoint. For distributor-scoped activity, see [Distributor Activity](/sdk/earn-api/deposits). To pick between the three views (positions, wallet activity, distributor activity), see the [Portfolio & Activity overview](/sdk/portfolio/overview).
## Endpoint
### Get Wallet Activity
```bash curl theme={null}
curl "https://earn.turtle.xyz/v2/wallets/activity/?addresses=0x3191F53d4d652F9cF37F74c554070d95e710c07f&page=1&limit=20" \
-H "X-API-Key: pk_live_xxxxx"
```
```typescript TypeScript theme={null}
const response = await fetch(
'https://earn.turtle.xyz/v2/wallets/activity/?addresses=0x3191F53d4d652F9cF37F74c554070d95e710c07f&page=1&limit=20',
{ headers: { 'X-API-Key': 'pk_live_xxxxx' } }
);
const data = await response.json();
```
**Query Parameters**
Comma-separated list of EVM wallet addresses. Maximum 1000 addresses per request. Addresses are case-insensitive.
Page number for pagination.
Results per page (max: 100).
This is a GET endpoint. Pass all parameters in the query string; do not send a request body.
## Response Example
```json theme={null}
{
"activity": [
{
"id": "uuid",
"opportunityId": "uuid",
"interaction": "deposit",
"txHash": "0xabc...",
"chainId": 1,
"blockTimestamp": "2024-11-01T12:00:00Z",
"walletAddress": "0xabc...",
"amountToken": "100.00",
"amountInUsd": "99.50",
"tokenSymbol": "USDC",
"tokenIconUrl": "https://...",
"isSwap": false
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 42,
"totalPages": 3,
"hasNext": true,
"hasPrevious": false
}
}
```
## Response Fields
Array of activity items. Each item uses the same activity-item shape as the deposit items returned by [Distributor Activity](/sdk/earn-api/deposits), with one difference: `interaction` is `deposit` or `withdraw` here, where the distributor endpoint always returns `deposit`.
Type of interaction. One of `deposit` or `withdraw`.
Pagination metadata. Same shape as the pagination object on [Distributor Activity](/sdk/earn-api/deposits).
Current page number.
Results per page.
Total number of matching interactions.
Total number of pages.
Whether a next page exists.
Whether a previous page exists.
## Use Cases
### Display Wallet Transaction History
Build a transaction history view for a user's portfolio page.
```typescript theme={null}
const getWalletHistory = async (walletAddress: string) => {
const response = await fetch(
`https://earn.turtle.xyz/v2/wallets/activity/?addresses=${walletAddress}&limit=50`,
{ headers: { 'X-API-Key': 'pk_live_xxxxx' } }
);
const { activity, pagination } = await response.json();
return { activity, pagination };
};
```
### Query Multiple Wallets
Fetch activity across multiple wallets in a single request. Useful for users with multiple addresses or for building aggregate views.
```typescript theme={null}
const addresses = [
'0x3191F53d4d652F9cF37F74c554070d95e710c07f',
'0xa1E7Db8d88BEd2bA0bEFb9bda654b98631c4b305'
].join(',');
const response = await fetch(
`https://earn.turtle.xyz/v2/wallets/activity/?addresses=${addresses}&page=1&limit=100`,
{ headers: { 'X-API-Key': 'pk_live_xxxxx' } }
);
const { activity } = await response.json();
```
### Paginate Through All Results
```typescript theme={null}
const getAllActivity = async (walletAddress: string) => {
let page = 1;
let allActivity = [];
while (true) {
const response = await fetch(
`https://earn.turtle.xyz/v2/wallets/activity/?addresses=${walletAddress}&page=${page}&limit=100`,
{ headers: { 'X-API-Key': 'pk_live_xxxxx' } }
);
const { activity, pagination } = await response.json();
allActivity.push(...activity);
if (!pagination.hasNext) break;
page++;
}
return allActivity;
};
```
## Wallet Activity vs Distributor Activity
| | Wallet Activity | [Distributor Activity](/sdk/earn-api/deposits) |
| ---------------- | ------------------------------ | ---------------------------------------------- |
| **Endpoint** | `GET /v2/wallets/activity/` | `GET /v2/deposit/{distributorId}` |
| **Scoped by** | Wallet address(es) | Distributor ID |
| **Interactions** | Deposits + withdrawals | Deposits only |
| **Best for** | Portfolio UIs, user dashboards | Distributor attribution tracking |
| **Pagination** | Page-based (`page`, `limit`) | Page-based (`page`, `limit`) |
## Error Handling
**Status Code:** 400 Bad Request
```json theme={null}
{
"error": {
"status": "INVALID_ARGUMENT",
"error": "addresses parameter is required"
}
}
```
**Solution:** Include at least one valid EVM address in the `addresses` query parameter.
**Status Code:** 400 Bad Request
```json theme={null}
{
"error": {
"status": "INVALID_ARGUMENT",
"error": "maximum 1000 addresses per request"
}
}
```
**Solution:** Split your request into batches of 1000 addresses or fewer.
**Status Code:** 400 Bad Request
**Solution:** This is a GET endpoint. Remove any request body and pass parameters via the query string only.
# Overview
Source: https://docs.turtle.xyz/sdk/portfolio/overview
Choose the right endpoint for positions, wallet activity, or distributor activity.
Three endpoints answer three different questions about what is happening with funds. Pick by the question you are answering, not by the resource name.
What does a wallet currently hold, across every supported protocol? Live balances and net value.
What has a wallet done? Deposit and withdrawal history for one or more addresses, across all distributors.
What flowed through my integration? Deposits attributed to your distributor.
## Choosing the right endpoint
| Question | Endpoint |
| --------------------------------------------------- | ---------------------------------------------- |
| What does this wallet hold right now? | [Positions](/sdk/portfolio/positions) |
| What deposits and withdrawals has this wallet made? | [Wallet Activity](/sdk/portfolio/activity) |
| Which deposits were attributed to my distributor? | [Distributor Activity](/sdk/earn-api/deposits) |
The split that trips people up is Wallet Activity versus Distributor Activity. Wallet Activity is scoped by wallet address and spans every distributor; Distributor Activity is scoped by your distributor ID. Both return the same per-interaction shape. Use Wallet Activity for user-facing portfolio history, and Distributor Activity for attribution and volume reporting.
# User Positions
Source: https://docs.turtle.xyz/sdk/portfolio/positions
Current on-chain DeFi positions for a wallet across supported protocols.
Send your API key via the `X-API-Key` header. See [Authentication](/sdk/authentication/api-keys).
## Overview
Return a wallet's **current** DeFi positions across every supported protocol (Uniswap, Aave, Euler, Morpho, Curvance, Pendle), grouped by protocol with per-position and total USD valuations. Positions are derived from on-chain state.
This is a point-in-time snapshot. For transaction history (deposits and withdrawals over time) use [Wallet Activity](/sdk/portfolio/activity).
## Endpoint
```bash curl theme={null}
curl -X GET "https://earn.turtle.xyz/v2/wallet/0xe84ef330b7b5c02fb3fbe05f2a31cb331c2b874c/portfolio" \
-H "X-API-Key: pk_live_xxxxx"
```
```typescript TypeScript theme={null}
const res = await fetch(
'https://earn.turtle.xyz/v2/wallet/0xe84ef330b7b5c02fb3fbe05f2a31cb331c2b874c/portfolio',
{ headers: { 'X-API-Key': 'pk_live_xxxxx' } }
);
const { total_stats, protocols } = await res.json();
```
**Path Parameters**
EVM wallet address.
**Response**
```json theme={null}
{
"total_stats": {
"asset_usd_value": "50000.00",
"debt_usd_value": "0.00",
"net_usd_value": "50000.00"
},
"protocols": [
{
"id": "morpho",
"name": "Morpho",
"site_url": "https://morpho.org",
"logo_url": "https://...",
"stats": { "asset_usd_value": "50000.00", "debt_usd_value": "0.00", "net_usd_value": "50000.00" },
"portfolio_item_list": [
{
"type": "yield",
"name": "Gauntlet USDC Core",
"detail": {
"supply_token_list": [
{ "address": "0xa0b8...eb48", "chain": "1", "symbol": "USDC", "name": "USD Coin", "decimals": 6, "amount": "50000.0", "price": "1.00", "logo_url": "https://..." }
]
},
"stats": { "asset_usd_value": "50000.00", "debt_usd_value": "0.00", "net_usd_value": "50000.00" },
"pool": { "id": "0x...", "chain": "1" }
}
]
}
]
}
```
Wallet-wide totals across all protocols: `asset_usd_value`, `debt_usd_value`, `net_usd_value`.
One entry per protocol the wallet holds positions in.
Protocol slug (e.g. `morpho`, `aave3`, `uniswap3`).
Protocol-level USD totals (`asset_usd_value`, `debt_usd_value`, `net_usd_value`).
Individual positions within the protocol.
Position type: `yield`, `lending`, `collateral`, or `liquidity`.
Token lists for the position: `supply_token_list`, and where relevant `borrow_token_list` / `reward_token_list`. Each token carries `address`, `chain`, `symbol`, `name`, `decimals`, `amount`, `price`, `logo_url`.
Pool / vault identifier for the position: `id` (contract address) and `chain`.
# API Explorer
Source: https://docs.turtle.xyz/sdk/reference/api-explorer
Browse and try the Turtle Earn API against its OpenAPI specification.
The Turtle Earn API publishes a machine-readable OpenAPI 3.1 specification. Use it to browse every public endpoint, generate a typed client, or drive an interactive playground.
**Spec URL:** `https://earn.turtle.xyz/docs/openapi.json`
## Browse the endpoints
The hosted Swagger UI lists every public endpoint with its parameters, request bodies, and response schemas:
* **Swagger UI:** [earn.turtle.xyz/docs](https://earn.turtle.xyz/docs)
The endpoints documented in this section (Authentication, Opportunities, Earn, Portfolio & Activity, Streams) are the partner-facing surface of that spec.
## Import into a client
Point any OpenAPI-aware tool at the spec URL:
* **Postman or Insomnia:** import by URL for an interactive collection.
* **Swagger UI or Redoc, locally:** load the spec URL to browse offline.
## Generate a typed client
```bash TypeScript theme={null}
npx @openapitools/openapi-generator-cli generate \
-i https://earn.turtle.xyz/docs/openapi.json \
-g typescript-fetch \
-o ./turtle-client
```
```bash Python theme={null}
openapi-generator-cli generate \
-i https://earn.turtle.xyz/docs/openapi.json \
-g python \
-o ./turtle-client
```
After generating, configure the client with your `X-API-Key` header. See [API Keys](/sdk/authentication/api-keys).
The spec is generated from the live API and reflects only the public endpoints. For the raw URL and more client-generation detail, see [OpenAPI Spec](/sdk/reference/openapi-spec).
# Changelog
Source: https://docs.turtle.xyz/sdk/reference/changelog
Track changes to the Turtle Earn API.
## July 2026
**Deposit and withdraw: on-chain balance preflight**
* Deposit and withdraw endpoints now read the user's on-chain balance of `tokenIn` (or vault shares, for withdraw) before building the transactions.
* Requests where the wallet holds less than `amount` are rejected up front with `400 INVALID_ARGUMENT` and error `insufficient token balance`, instead of failing later on-chain.
* Documented on the [Deposit](/sdk/earn/deposit#error-handling) and [Withdraw](/sdk/earn/withdraw#error-handling) pages under Error Handling.
**Streams: 1.5% creation fee, with Turtle Pro exempt**
* Token streams now include a **1.5% creation fee**, charged in the reward token and pulled at stream creation on top of the net reward budget. Point streams remain free.
* **Turtle Pro organizations are exempt** (0%).
* The exact fee is surfaced as `FeeAmount` in the [create-stream](/sdk/streams/create-stream) response and shown on the Client Portal review screen before you confirm.
* See [Streams: before you start](/partner-products/streams/before-you-start) for prerequisites and funding requirements.
**Genesis Airdrop: in-app claiming**
* Eligible wallets can now check allocations and claim \$TURTLE directly in the [Turtle app](https://app.turtle.xyz) under **Your Earnings** on the [Liquidity Campaigns page](https://app.turtle.xyz/deals).
* Allocations are bound to the wallet used to contribute to the Turtle DAO — connecting a different wallet will show nothing to claim.
* Claiming once forfeits any unvested portion. Review [Vesting & Mechanics](/token/airdrop#vesting--mechanics) before you claim.
* Full walkthrough: [Genesis Airdrop](/token/airdrop).
## April 2026
**Documentation revamp**
* Added new pages: Authentication Overview, Opportunities Overview, Historical Data (stub), Earn API Overview, Swap Mode, Async Deposits, Portfolio Overview, Streams Overview, Distributor Model, Error Codes, OpenAPI Spec, and Changelog
* Removed Route API page
* Removed the `POST /v1/actions/attribute` endpoint; attribution is now fully automatic and documented in the [Distributor Model](/sdk/concepts/distributor-model) concept
* Retitled the distributor deposits page to "Distributor Activity" and grouped it with the wallet-scoped activity and positions endpoints under "Portfolio & Activity"
* Added three previously undocumented response fields to Opportunities: `minDepositAmountUsd`, `swapDirectEnabled`, `swapRouteEnabled`
* Added three previously undocumented query filters to Opportunities: `chainIds`, `depositToken`, `tvlGreaterThan`
# Error Codes
Source: https://docs.turtle.xyz/sdk/reference/error-codes
Standard HTTP error responses across all Earn API endpoints.
All endpoints return errors in a consistent shape with `code`, `status`, `error` string, and `context` object. Each endpoint page repeats the codes that matter for that call in its own Error Handling section; this table is the cross-cutting reference.
```json Error Response Shape theme={null}
{
"code": 400,
"status": "INVALID_ARGUMENT",
"error": "Description of what went wrong",
"context": {
"field": "Additional context about the error"
}
}
```
## Error reference
| Status Code | Error | When It Occurs | How to Handle |
| ------------------------- | ------------------ | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| 400 Bad Request | `INVALID_ARGUMENT` | Invalid parameters or missing required fields | Check request body and query params against the API reference |
| 401 Unauthorized | `UNAUTHORIZED` | Invalid or missing API key | Verify your `pk_live_` or `sk_live_` key is set on the `X-API-Key` header. See [API Keys](/sdk/authentication/api-keys) |
| 404 Not Found | `NOT_FOUND` | Opportunity, distributor, or membership not found | Confirm the ID exists and the wallet is a member. See [Register Wallet](/sdk/authentication/register-wallet) |
| 409 Conflict | `CONFLICT` | Membership already exists for this wallet address | Call `GET /v2/membership/` first to check before creating. See [Register Wallet](/sdk/authentication/register-wallet) |
| 500 Internal Server Error | `INTERNAL` | Server-side failure | Retry with exponential backoff, contact [support](https://discord.turtle.xyz) if persistent |
# OpenAPI Spec
Source: https://docs.turtle.xyz/sdk/reference/openapi-spec
Access the Turtle Earn API spec for SDK generation and API testing.
The Turtle Earn API publishes an OpenAPI 3.0 specification that you can use for client generation, API testing, and documentation tooling.
**Raw spec URL:** `https://earn.turtle.xyz/docs/openapi.json`
## What you can do with it
* Import into Postman or Insomnia for interactive API testing
* Generate TypeScript or Python clients with `openapi-generator`
* Use with Swagger UI locally for browsing endpoints
## Generate a TypeScript client
```bash curl theme={null}
npx @openapitools/openapi-generator-cli generate \
-i https://earn.turtle.xyz/docs/openapi.json \
-g typescript-fetch \
-o ./turtle-client
```
```typescript TypeScript theme={null}
// After generating, import and use the client:
import { OpportunitiesApi, Configuration } from './turtle-client';
const config = new Configuration({
headers: { 'X-API-Key': 'pk_live_xxxxx' },
});
const api = new OpportunitiesApi(config);
const opportunities = await api.getOpportunities();
```
The spec is generated from the live API. Three fields confirmed in the raw spec are now documented on the [Opportunities](/sdk/opportunities/get-opportunities) page: `minDepositAmountUsd`, `swapDirectEnabled`, `swapRouteEnabled`.
# Claim Rewards
Source: https://docs.turtle.xyz/sdk/streams/claim-rewards
Integrate on-chain reward claiming for token streams into your application
## Overview
Claiming rewards from a token stream is a two-step process:
1. **Fetch the Merkle proof** from the Turtle API ([Get Merkle Proofs](/sdk/streams/get-merkle-proofs))
2. **Submit a claim transaction** to the stream's smart contract on-chain
No API key is needed for either step. Proofs are permissionless, and claiming is a direct on-chain interaction.
```
Your Application
↓ 1. GET /v2/streams/merkle_proofs
earn.turtle.xyz
↓ 2. Returns proof + amount + timestamp + contract address
Your Application
↓ 3. Build claim transaction
Stream Contract (on-chain)
↓ 4. User signs & submits
Rewards transferred to user wallet
```
## Contract ABI
The stream contract exposes the following functions for claiming and display. This ABI is sufficient for all claim integration scenarios.
### Stream contract
Each stream is a separate contract. The address is returned in the [Merkle proof API response](/sdk/streams/get-merkle-proofs) as `contractAddress`.
```typescript theme={null}
const STREAM_ABI = [
"function claim(uint256 amount, uint40 timestamp, bytes32[] merkleProof) external returns (uint256)",
"function canClaim(address user, uint256 amount, uint40 timestamp, bytes32[] merkleProof) external view returns (uint256)",
"function getClaimedRewards(address user) external view returns (uint256)",
"function getRewardToken() external view returns (address)"
];
```
| Function | Type | Purpose |
| ------------------- | ----- | ---------------------------------------------- |
| `claim` | Write | Claim rewards for the connected wallet |
| `canClaim` | View | Returns the unclaimed amount (use for display) |
| `getClaimedRewards` | View | Returns total already claimed by a user |
| `getRewardToken` | View | Returns the reward token address |
### StreamFactory contract
The StreamFactory owns all stream contracts and provides batch operations. Use it to claim from multiple streams in a single transaction.
```typescript theme={null}
const STREAM_FACTORY_ABI = [
"function batchClaim((address stream, uint256 amount, uint40 rootTimestamp, bytes32[] merkleProof)[] claims, bool revertOnFailure) external returns (bool[])",
"function batchClaimFor(address user, (address stream, uint256 amount, uint40 rootTimestamp, bytes32[] merkleProof)[] claims, bool revertOnFailure) external returns (bool[])",
"function toggleOperatorForUser(address user, address operator) external"
];
```
| Function | Type | Purpose |
| ----------------------- | ----- | ------------------------------------------------------ |
| `batchClaim` | Write | Claim from multiple streams in one transaction |
| `batchClaimFor` | Write | Claim on behalf of a user (requires operator approval) |
| `toggleOperatorForUser` | Write | Approve or revoke an operator for a user |
## Show claimable amount
Call `canClaim()` as a `staticCall` (no gas, no transaction) to display the unclaimed balance before the user clicks "Claim." It takes the same parameters from the [Merkle proof API response](/sdk/streams/get-merkle-proofs) plus the user's address.
```typescript theme={null}
import { ethers } from 'ethers';
const STREAM_ABI = [
"function canClaim(address user, uint256 amount, uint40 timestamp, bytes32[] merkleProof) external view returns (uint256)",
];
// 1. Fetch proof from Turtle API
const res = await fetch(
`https://earn.turtle.xyz/v2/streams/merkle_proofs?wallet=${userAddress}&streamIds=${streamId}`
);
const { proofs } = await res.json();
const proof = proofs[0];
// 2. Convert timestamp from ISO 8601 to Unix epoch (uint40)
const timestamp = Math.floor(new Date(proof.timestamp).getTime() / 1000);
// 3. Call canClaim (staticCall, no gas)
const provider = new ethers.BrowserProvider(window.ethereum);
const contract = new ethers.Contract(proof.contractAddress, STREAM_ABI, provider);
const claimable = await contract.canClaim(
userAddress,
proof.amount,
timestamp,
proof.proof
);
console.log('Claimable:', ethers.formatUnits(claimable, 18));
```
`canClaim()` returns the actual unclaimed amount. No additional math required. It accounts for previous claims automatically.
## Claim rewards
Submit a `claim()` transaction using the proof data. The contract uses a **cumulative model**: `amount` is the user's total allocation across all snapshots, and the contract releases only the difference between the total and what has already been claimed.
```typescript theme={null}
import { ethers } from 'ethers';
const STREAM_ABI = [
"function claim(uint256 amount, uint40 timestamp, bytes32[] merkleProof) external returns (uint256)",
"function canClaim(address user, uint256 amount, uint40 timestamp, bytes32[] merkleProof) external view returns (uint256)",
];
// 1. Fetch proof
const res = await fetch(
`https://earn.turtle.xyz/v2/streams/merkle_proofs?wallet=${userAddress}&streamIds=${streamId}`
);
const { proofs } = await res.json();
const proof = proofs[0];
// 2. Convert timestamp from ISO 8601 to Unix epoch (uint40)
const timestamp = Math.floor(new Date(proof.timestamp).getTime() / 1000);
// 3. Connect signer
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const contract = new ethers.Contract(proof.contractAddress, STREAM_ABI, signer);
// 4. (Optional) Show claimable amount first
const claimable = await contract.canClaim(
userAddress,
proof.amount,
timestamp,
proof.proof
);
console.log('Claimable:', ethers.formatUnits(claimable, 18));
// 5. Submit claim transaction
const tx = await contract.claim(
proof.amount, // total cumulative allocation
timestamp, // Merkle root timestamp (uint40)
proof.proof // Merkle proof (bytes32[])
);
const receipt = await tx.wait();
console.log('Claimed successfully:', receipt.hash);
```
## Batch claiming
If a user has rewards across multiple streams, you can claim all of them in a single transaction using `batchClaim()` on the StreamFactory instead of calling `claim()` on each stream contract separately.
```typescript theme={null}
import { ethers } from 'ethers';
const STREAM_FACTORY_ABI = [
"function batchClaim((address stream, uint256 amount, uint40 rootTimestamp, bytes32[] merkleProof)[] claims, bool revertOnFailure) external returns (bool[])",
];
// 1. Fetch proofs for all streams
const params = new URLSearchParams({ wallet: userAddress });
streamIds.forEach((id) => params.append('streamIds', id));
const res = await fetch(
`https://earn.turtle.xyz/v2/streams/merkle_proofs?${params}`
);
const { proofs } = await res.json();
// 2. Build batch claims array
const claims = proofs
.filter((p) => p.amount && p.amount !== '0')
.map((p) => ({
stream: p.contractAddress,
amount: p.amount,
rootTimestamp: Math.floor(new Date(p.timestamp).getTime() / 1000),
merkleProof: p.proof,
}));
// 3. Submit single batch transaction to the StreamFactory
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const factory = new ethers.Contract(STREAM_FACTORY_ADDRESS, STREAM_FACTORY_ABI, signer);
const tx = await factory.batchClaim(claims, true); // revertOnFailure=true
const receipt = await tx.wait();
```
The StreamFactory address depends on the chain. Contact Turtle or check the block explorer for the deployed address on your target network.
## Claim on behalf of a user
To claim on behalf of another user, use `batchClaimFor()` on the StreamFactory. The caller must first be approved as an **operator** by the user via `toggleOperatorForUser()`.
```typescript theme={null}
// User approves the operator (one-time setup)
const tx1 = await factory.toggleOperatorForUser(userAddress, operatorAddress);
await tx1.wait();
// Operator claims on behalf of the user
const tx2 = await factory.batchClaimFor(userAddress, claims, true);
await tx2.wait();
```
`claim()` on the stream contract can only be called by the user themselves. Delegated claiming always goes through the StreamFactory's `batchClaimFor()` with prior operator approval.
## React component
A drop-in `` component for React/Next.js applications. It fetches proofs, displays the claimable amount, and handles the claim transaction.
```tsx theme={null}
import { useState, useEffect } from 'react';
import { ethers } from 'ethers';
const STREAM_ABI = [
"function claim(uint256 amount, uint40 timestamp, bytes32[] merkleProof) external returns (uint256)",
"function canClaim(address user, uint256 amount, uint40 timestamp, bytes32[] merkleProof) external view returns (uint256)",
];
interface ClaimButtonProps {
streamIds: string[]; // stream UUIDs to claim from
walletAddress: string; // connected wallet
provider: ethers.Provider; // provider for read calls
signer: ethers.Signer; // wallet signer for claim tx
onSuccess?: (receipt: ethers.TransactionReceipt) => void;
onError?: (error: Error) => void;
}
export function StreamsClaimButton({
streamIds,
walletAddress,
provider,
signer,
onSuccess,
onError,
}: ClaimButtonProps) {
const [loading, setLoading] = useState(false);
const [status, setStatus] = useState('');
const [claimable, setClaimable] = useState(null);
// Fetch proofs and check claimable amount on mount
useEffect(() => {
(async () => {
try {
const ids = streamIds.join('&streamIds=');
const res = await fetch(
`https://earn.turtle.xyz/v2/streams/merkle_proofs?wallet=${walletAddress}&streamIds=${ids}`
);
const { proofs } = await res.json();
if (!proofs || proofs.length === 0) return;
let total = 0n;
for (const proof of proofs) {
if (!proof.amount || proof.amount === '0') continue;
const contract = new ethers.Contract(
proof.contractAddress,
STREAM_ABI,
provider
);
const ts = Math.floor(new Date(proof.timestamp).getTime() / 1000);
const amount = await contract.canClaim(
walletAddress,
proof.amount,
ts,
proof.proof
);
total += amount;
}
setClaimable(ethers.formatUnits(total, 18));
} catch {
// Silently fail: button still works without display amount
}
})();
}, [streamIds, walletAddress, provider]);
const handleClaim = async () => {
setLoading(true);
setStatus('Fetching proof...');
try {
const ids = streamIds.join('&streamIds=');
const res = await fetch(
`https://earn.turtle.xyz/v2/streams/merkle_proofs?wallet=${walletAddress}&streamIds=${ids}`
);
const { proofs } = await res.json();
if (!proofs || proofs.length === 0) {
setStatus('No claimable rewards found');
setLoading(false);
return;
}
for (const proof of proofs) {
if (!proof.amount || proof.amount === '0') continue;
setStatus(`Claiming from ${proof.contractAddress.slice(0, 8)}...`);
const ts = Math.floor(new Date(proof.timestamp).getTime() / 1000);
const contract = new ethers.Contract(
proof.contractAddress,
STREAM_ABI,
signer
);
const tx = await contract.claim(
proof.amount,
ts,
proof.proof
);
const receipt = await tx.wait();
onSuccess?.(receipt);
}
setClaimable('0');
setStatus('Claimed!');
} catch (err) {
setStatus('Claim failed');
onError?.(err as Error);
} finally {
setLoading(false);
}
};
return (
);
}
```
**Usage:**
```tsx theme={null}
console.log('Claimed:', receipt)}
onError={(err) => console.error('Failed:', err)}
/>
```
## Operational Notes
The `amount` parameter in `claim()` is the user's **total cumulative allocation**, not the unclaimed delta. The contract tracks how much has already been claimed and releases only the difference. Users can claim at any time and always receive their full outstanding balance in a single transaction.
The `amount` from the API is in raw token units. Use `ethers.formatUnits(amount, decimals)` to convert to a human-readable number for display. Call `getRewardToken()` on the contract to get the token address, then query the token's `decimals()` if needed (most stream reward tokens use 18 decimals). Always pass the raw value to the contract. Do not format it before sending the transaction.
The API returns `timestamp` as an ISO 8601 string (e.g. `"2026-05-20T13:05:10Z"`), but the contract expects a `uint40` Unix epoch in seconds. Convert before passing to the contract: `Math.floor(new Date(proof.timestamp).getTime() / 1000)`.
Each stream has its own contract. When calling `claim()` directly, you need a separate transaction per stream. The React component above handles this automatically. Alternatively, use `batchClaim()` on the StreamFactory to claim from all streams in a single transaction.
Calling `claim()` when there is nothing new to claim will succeed but transfer zero tokens. There is no penalty for calling it multiple times.
# Create Point
Source: https://docs.turtle.xyz/sdk/streams/create-point
Create a point asset for the organization associated with the API key
All requests require an API key via the `X-API-Key` header.
See [Authentication](/sdk/authentication/api-keys) for details.
## Overview
`POST /v2/streams/points` creates a point asset for the organization associated with the API key.
Points are used as reward assets for point-based streams. Creating a point lets your organization define a symbol, display name, precision, and optional logo for those rewards.
You only need this endpoint if you plan to create point-based streams. It is not required for streams that use `rewardToken`.
The API key must belong to an organization and that organization must have the `organization:incentivize:streams:create` permission.
## Endpoint
```bash curl theme={null}
curl -X POST "https://earn.turtle.xyz/v2/streams/points" \
-H "X-API-Key: sk_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"symbol": "PTS",
"name": "Partner Points",
"decimals": 18,
"logoUrl": "https://cdn.example.com/points/pts.png"
}'
```
```typescript TypeScript theme={null}
const response = await fetch('https://earn.turtle.xyz/v2/streams/points', {
method: 'POST',
headers: {
'X-API-Key': process.env.TURTLE_SECRET_KEY!,
'Content-Type': 'application/json',
},
body: JSON.stringify({
symbol: 'PTS',
name: 'Partner Points',
decimals: 18,
logoUrl: 'https://cdn.example.com/points/pts.png',
}),
});
const data = await response.json();
```
## Request Body
Point symbol.
Point name.
Decimal precision for the point asset. If omitted, it uses the default configured precision of `18`.
Optional logo URL for the point asset.
## Response Example
```json theme={null}
{
"point": {
"id": "7ff13cf6-53d0-4f3e-bd1a-e8eab6db4cf1",
"orgId": "9f51b66a-d13a-4b55-8515-ae6e4ef7cf25",
"symbol": "PTS",
"name": "Partner Points",
"decimals": 18,
"logoUrl": "https://cdn.example.com/points/pts.png",
"createdAt": "2026-03-01T00:00:00Z",
"updatedAt": "2026-03-01T00:00:00Z"
}
}
```
```typescript theme={null}
point: Point
```
## Response Fields
The newly created point asset.
### `Point`
Unique point identifier.
Organization that owns the point.
Normalized uppercase point symbol.
Point name.
Decimal precision assigned to the point asset.
Optional logo URL associated with the point asset.
Creation timestamp of the point.
Last update timestamp of the point.
## Important Notes
The backend trims whitespace and uppercases `symbol` before persisting the point.
If `decimals` is omitted, Turtle uses the configured default point precision, currently `18`.
Organizations using ERC-20 rewards through `rewardToken` do not need to create points. Points are only used with `pointId` in point-based stream creation.
## Error Handling
**Status Code:** 401 Unauthorized
```json theme={null}
{
"error": "Invalid API key"
}
```
**Solution:** Pass a valid `X-API-Key` header belonging to an organization-scoped API key.
**Status Code:** 400 Bad Request
```json theme={null}
{
"error": {
"status": "INVALID_ARGUMENT",
"error": "symbol is required"
}
}
```
**Common causes:**
* `symbol` is missing or blank
* `name` is missing or blank
**Status Code:** 403 Forbidden
```json theme={null}
{
"error": {
"status": "PERMISSION_DENIED",
"error": "permission denied"
}
}
```
**Solution:** Use an API key associated with an organization that has the `organization:incentivize:streams:create` permission.
**Status Code:** 500 Internal Server Error
**Solution:** Retry the request and contact Turtle if the issue persists.
# Create Stream
Source: https://docs.turtle.xyz/sdk/streams/create-stream
Create token-based or point-based incentive streams for your organization
All requests require an API key via the `X-API-Key` header.
See [Authentication](/sdk/authentication/api-keys) for details.
To create streams, the organization attached to the API key must also have permission to create streams. If your organization still does not have that permission enabled, contact the Turtle team to request it.
## Overview
`POST /v2/streams/` creates a new incentive stream owned by the organization attached to the API key.
There are two creation flows:
* **Token-based stream:** the API validates the request, stores the pending stream, and returns `txParams` with the backend-signed authorization that your wallet must submit on-chain to the corresponding `StreamFactory`.
* **Point-based stream:** the API creates the stream immediately and returns `txParams: null`.
Points are only used for point-based streams. If your stream uses `rewardTokenId`, you do not need to create or reference a point.
A stream can use both `rewardTokenId` and `targetTokenId` on the same chain. The difference is support scope, not a requirement to split them across networks. Reward-token selection is currently supported only for stream creation on 5 networks: Ethereum, Base, Avalanche, BSC, and Sepolia. `targetTokenId` supports a broader set of chains through [Get Tokens](/sdk/streams/get-tokens), where the lookup uses the decimal EVM `chainId`.
## Supported Stream Types
| Type | Strategy | Required behavior |
| ---- | -------------- | ------------------------------------------------------------------------------------------- |
| `1` | `Fixed Rate` | `totalAmount` required for token-based streams |
| `2` | `Fixed APR` | `rewardTokenId` and `totalAmount` required |
| `3` | `Daily Budget` | `totalAmount` must be omitted; `endTimestamp` required for token-based |
| `4` | `Airdrop` | `rewardTokenId` and `totalAmount` required; snapshots uploaded manually |
| `5` | `Yield Match` | `rewardTokenId` and `totalAmount` required; set `targetApy` for gap-fill or omit for mirror |
## Create a Token-Based Stream
If you are creating a token-based stream, use [Get Tokens](/sdk/streams/get-tokens) to list the supported reward-token UUIDs (`rewardTokenId`) for the selected chain, or to discover supported target tokens used in strategy `customArgs` (for example, `targetTokenId`). For `rewardTokenId`, choose a token where `isAllowedRewardToken` is `true`.
For token-based streams, the `totalAmount` specified in the request is the exact amount used in the on-chain stream-creation transaction. This amount must already be available in the submitting wallet, as it will be transferred to the smart contract when the stream creation is finalized on-chain.
```bash curl theme={null}
curl -X POST "https://earn.turtle.xyz/v2/streams/" \
-H "X-API-Key: sk_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"walletAddress": "0x1111111111111111111111111111111111111111",
"type": 2,
"rewardTokenId": "56b0fab0-5c3e-49f6-a0a7-57e38d5ea999",
"totalAmount": "2500000000000000000000",
"startTimestamp": "2026-03-20T00:00:00Z",
"endTimestamp": "2026-04-20T00:00:00Z",
"customArgs": {
"targetTokenId": "8cc2ed9d-bd59-42fd-9df5-329fa22497b6",
"apr": "0.12"
},
"adapters": []
}'
```
```typescript TypeScript theme={null}
const response = await fetch('https://earn.turtle.xyz/v2/streams/', {
method: 'POST',
headers: {
'X-API-Key': process.env.TURTLE_SECRET_KEY!,
'Content-Type': 'application/json',
},
body: JSON.stringify({
walletAddress: '0x1111111111111111111111111111111111111111',
type: 2,
rewardTokenId: '56b0fab0-5c3e-49f6-a0a7-57e38d5ea999',
totalAmount: '2500000000000000000000',
startTimestamp: '2026-03-20T00:00:00Z',
endTimestamp: '2026-04-20T00:00:00Z',
customArgs: {
targetTokenId: '8cc2ed9d-bd59-42fd-9df5-329fa22497b6',
apr: '0.12',
},
adapters: [],
}),
});
const data = await response.json();
```
## Create a Point-Based Stream
If you are creating a point-based stream and do not yet have a point asset for your organization, use [Create Point](/sdk/streams/create-point) first. You can list existing organization points with [Get Points](/sdk/streams/get-points).
```bash curl theme={null}
curl -X POST "https://earn.turtle.xyz/v2/streams/" \
-H "X-API-Key: sk_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"type": 1,
"pointId": "9a598b70-c6f9-4a1f-9357-3a5823a7ce36",
"totalAmount": "5000000000000000000000",
"startTimestamp": "2026-03-20T00:00:00Z",
"endTimestamp": "2026-04-20T00:00:00Z",
"customArgs": {
"targetTokenId": "8cc2ed9d-bd59-42fd-9df5-329fa22497b6",
"tokensPerUSD": "1000000000000000"
},
"adapters": []
}'
```
```typescript TypeScript theme={null}
const response = await fetch('https://earn.turtle.xyz/v2/streams/', {
method: 'POST',
headers: {
'X-API-Key': process.env.TURTLE_SECRET_KEY!,
'Content-Type': 'application/json',
},
body: JSON.stringify({
type: 1,
pointId: '9a598b70-c6f9-4a1f-9357-3a5823a7ce36',
totalAmount: '5000000000000000000000',
startTimestamp: '2026-03-20T00:00:00Z',
endTimestamp: '2026-04-20T00:00:00Z',
customArgs: {
targetTokenId: '8cc2ed9d-bd59-42fd-9df5-329fa22497b6',
tokensPerUSD: '1000000000000000',
},
adapters: [],
}),
});
const data = await response.json();
```
## Request Body
Admin EVM address for token-based streams. Must be omitted for point-based streams.
Stream type. Supported values are `1` (Fixed Rate), `2` (Fixed APR), `3` (Daily Budget), `4` (Airdrop), and `5` (Yield Match).
Reward token UUID (use the token `id` from [Get Tokens](/sdk/streams/get-tokens)) for token-based streams. Exactly one of `rewardTokenId` or `pointId` must be provided. Choose a token where `isAllowedRewardToken` is `true`. Reward-token selection for stream creation is currently limited to Ethereum, Base, Avalanche, BSC, and Sepolia; `rewardTokenId` will be resolved by the server into the token address and chain used for on-chain creation.
Point identifier for point-based streams only. Exactly one of `rewardTokenId` or `pointId` must be provided. See [Get Points](/sdk/streams/get-points) for the `Point` schema and examples.
Total rewards in base units. Required for Fixed Rate, Fixed APR, Airdrop, and Yield Match streams. Must be omitted for Daily Budget streams (calculated automatically from `tokensPerDay` and stream duration). For token-based streams, this is the amount that will be sent to the smart contract on-chain when the wallet submits the returned `txParams`, so the wallet must already hold the required balance.
UTC stream start timestamp. Must align to a 15-minute boundary.
Optional UTC stream end timestamp. If provided, it must be at least one hour after `startTimestamp` and aligned to a 15-minute boundary. Required for token-based Daily Budget streams.
Strategy-specific configuration object. See [customArgs by Type](#customargs-by-type) for details.
Optional adapter configuration array. Each adapter entry must include `type` and `params`.
## `customArgs` by Type
### Fixed Rate (`type = 1`)
```json theme={null}
{
"targetTokenId": "8cc2ed9d-bd59-42fd-9df5-329fa22497b6",
"tokensPerUSD": "1000000000000000"
}
```
* `targetTokenId`: supported target token used as the tracked balance source. Resolve it through [Get Tokens](/sdk/streams/get-tokens) using the decimal EVM `chainId` for the target-token network.
* `tokensPerUSD`: positive reward-emission coefficient in base units. Specifies the daily number of token/point wei units to grant for every 1,000 USD of provisioned TVL.
* `depositQualification` (optional): restrict rewards to capital attributed to specific distributors. See [Restrict rewards to attributed deposits](#restrict-rewards-to-attributed-deposits).
### Fixed APR (`type = 2`)
```json theme={null}
{
"targetTokenId": "8cc2ed9d-bd59-42fd-9df5-329fa22497b6",
"apr": "0.12"
}
```
* `targetTokenId`: supported target token used as the tracked balance source. Resolve it through [Get Tokens](/sdk/streams/get-tokens) using the decimal EVM `chainId` for the target-token network.
* `apr`: positive APR value expressed as a decimal fraction — multiply by 100 for the percentage (for example, `0.05` means 5%).
* `depositQualification` (optional): restrict rewards to capital attributed to specific distributors. See [Restrict rewards to attributed deposits](#restrict-rewards-to-attributed-deposits).
### Daily Budget (`type = 3`)
```json theme={null}
{
"targetTokenId": "8cc2ed9d-bd59-42fd-9df5-329fa22497b6",
"tokensPerDay": "1000000000000000000"
}
```
* `targetTokenId`: supported target token used as the tracked balance source. Resolve it through [Get Tokens](/sdk/streams/get-tokens) using the decimal EVM `chainId` for the target-token network.
* `tokensPerDay`: positive per-day reward budget in base units. This budget is split pro-rata among all holders. The total amount is calculated automatically from `tokensPerDay` multiplied by the stream duration.
* `depositQualification` (optional): restrict rewards to capital attributed to specific distributors. See [Restrict rewards to attributed deposits](#restrict-rewards-to-attributed-deposits).
### Airdrop (`type = 4`)
```json theme={null}
{
"targetTokenId": "8cc2ed9d-bd59-42fd-9df5-329fa22497b6"
}
```
* `targetTokenId`: supported target token used as the tracked balance source. Resolve it through [Get Tokens](/sdk/streams/get-tokens) using the decimal EVM `chainId` for the target-token network.
Airdrop streams do not compute rewards automatically. Instead, allocations are uploaded via a dedicated snapshot endpoint. Use this type for manual distributions, retroactive rewards, or any scenario where you determine allocations outside of Turtle's reward formulas.
### Yield Match (`type = 5`)
Yield Match streams operate in one of two modes, determined at creation by whether `targetApy` is set.
**Gap-fill mode** (recommended for most use cases):
```json theme={null}
{
"targetTokenId": "8cc2ed9d-bd59-42fd-9df5-329fa22497b6",
"targetApy": "0.12"
}
```
The stream pays the difference between the vault's native APY and the target. If the vault yields 7% and `targetApy` is 12%, the stream pays the 5% gap in reward tokens. If the vault exceeds the target, the stream pays nothing.
**Mirror mode:**
```json theme={null}
{
"targetTokenId": "8cc2ed9d-bd59-42fd-9df5-329fa22497b6",
"apyOffset": "0.02"
}
```
The stream mirrors the vault's APY in reward tokens, shifted by the optional `apyOffset`. With no offset, depositors earn double: the vault's native yield plus the same rate in reward tokens.
**Parameters:**
* `targetTokenId`: supported target token used as the tracked balance source.
* `targetApy` (gap-fill mode): positive target APY expressed as a decimal fraction — multiply by 100 for the percentage (for example, `0.05` means 5%). The stream fills the gap between vault APY and this target.
* `apyOffset` (mirror mode): offset added to the vault APY before computing the reward rate, expressed as a decimal fraction — multiply by 100 for the percentage (for example, `0.05` means 5%). Can be positive or negative.
* `targetApyTokenId` (optional): override the APY data source. Defaults to the holding token. Useful when the reward token's APY proxy lives on a different contract.
* `vaultApyLookbackDays` (optional): number of days used to estimate current vault APY. Defaults to 30.
* `dailyUSDRewardsCap` (optional): maximum daily reward spend in USD terms.
* `depositQualification` (optional): restrict rewards to capital attributed to specific distributors. See [Restrict rewards to attributed deposits](#restrict-rewards-to-attributed-deposits).
You cannot switch between gap-fill and mirror modes on a live stream. The mode is locked at creation.
## Restrict rewards to attributed deposits
`depositQualification` is an optional field on Fixed Rate, Fixed APR, Daily Budget, and Yield Match streams. It scopes rewards to the capital a wallet deposited through specific distributors, rather than the wallet's whole balance of the target token.
Use it when you want a campaign to reward only the capital brought in by one or more attribution partners — for example, deposits routed through the Turtle app or through a specific affiliate. Wallets that hold the target token but did not deposit through a qualified distributor accrue nothing.
```json theme={null}
{
"targetTokenId": "8cc2ed9d-bd59-42fd-9df5-329fa22497b6",
"apr": "0.12",
"depositQualification": {
"distributorIds": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"]
},
"mode": "fifo"
}
```
* `distributorIds` (optional): list of distributor UUIDs to accept. Each ID must be non-empty, trimmed, contain no commas, braces, quotes, or backslashes, and appear only once. Omit or pass `[]` to accept any qualified distributor.
* `mode` (required when `depositQualification` is set): lot-accounting mode used to determine which deposit lot a withdrawal drains. Either `fifo` (oldest lot first) or `lifo` (newest lot first). The two modes can produce different qualified TVL for the same wallet when some lots are attributed and others are not, so there is no default.
`depositQualification` is locked at creation. You cannot add, remove, or change it on a live stream — the customArgs-update endpoint rejects it. Changing it mid-stream would shift the reward basis between two consecutive snapshots.
`depositQualification` requires the target token's chain to have distributor attribution and a live deposit-metrics collector. If either is missing, [Create Stream](/sdk/streams/create-stream) returns a validation error identifying the unsupported target token.
## Response Examples
### Token-based response
```json theme={null}
{
"message": "Successfully generated signature for token-based stream",
"txParams": {
"chainId": 1,
"sender": "0x1111111111111111111111111111111111111111",
"params": {
"params": {
"StreamId": [85, 14, 132, 0, 226, 155, 65, 212, 167, 22, 68, 102, 85, 68, 0, 0],
"RewardToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"NetTotalAmount": "2500000000000000000000",
"FeeAmount": "0"
},
"deadline": "1773628800",
"signature": "MEUCIA...base64..."
}
},
"stream": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"chainId": 1,
"contractAddress": null,
"userId": null,
"orgId": "9f51b66a-d13a-4b55-8515-ae6e4ef7cf25",
"admin": "0x1111111111111111111111111111111111111111",
"type": 2,
"createdAt": "2026-03-20T00:00:00Z",
"updatedAt": "2026-03-20T00:00:00Z",
"startTimestamp": "2026-03-20T00:00:00Z",
"endTimestamp": "2026-04-20T00:00:00Z",
"totalAmount": "2500000000000000000000",
"creationConfirmedAt": null,
"snapshotComputationPaused": false,
"merkleTreeComputationPaused": false,
"hashCommitmentPaused": false,
"claimPaused": false,
"customArgs": {
"targetTokenId": "8cc2ed9d-bd59-42fd-9df5-329fa22497b6",
"apr": "0.12"
},
"adapters": [],
"point": null,
"strategy": "Fixed APR",
"lastSnapshot": null,
"committedSnapshot": null,
"rewardToken": {
"id": "56b0fab0-5c3e-49f6-a0a7-57e38d5ea999",
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"name": "USD Coin",
"symbol": "USDC",
"decimals": 6,
"chainId": 1,
"logoUrl": "https://cdn.example.com/tokens/usdc.png",
"isAllowedRewardToken": true
},
"estimatedLiveApr": null
}
}
```
### Point-based response
```json theme={null}
{
"message": "Successfully created point-based stream",
"txParams": null,
"stream": {
"id": "550e8400-e29b-41d4-a716-446655440001",
"chainId": null,
"contractAddress": null,
"userId": null,
"orgId": "9f51b66a-d13a-4b55-8515-ae6e4ef7cf25",
"admin": null,
"type": 1,
"createdAt": "2026-03-20T00:00:00Z",
"updatedAt": "2026-03-20T00:00:00Z",
"startTimestamp": "2026-03-20T00:00:00Z",
"endTimestamp": "2026-04-20T00:00:00Z",
"totalAmount": "5000000000000000000000",
"creationConfirmedAt": "2026-03-20T00:00:00Z",
"snapshotComputationPaused": false,
"merkleTreeComputationPaused": false,
"hashCommitmentPaused": false,
"claimPaused": false,
"customArgs": {
"targetTokenId": "8cc2ed9d-bd59-42fd-9df5-329fa22497b6",
"tokensPerUSD": "1000000000000000"
},
"adapters": [],
"point": {
"id": "9a598b70-c6f9-4a1f-9357-3a5823a7ce36",
"orgId": "9f51b66a-d13a-4b55-8515-ae6e4ef7cf25",
"symbol": "POINT",
"name": "Partner Points",
"decimals": 18,
"logoUrl": "https://cdn.example.com/points/partner-points.png",
"createdAt": "2026-03-01T00:00:00Z",
"updatedAt": "2026-03-01T00:00:00Z"
},
"strategy": "Fixed Rate",
"lastSnapshot": null,
"committedSnapshot": null,
"rewardToken": null,
"estimatedLiveApr": null
}
}
```
`estimatedLiveApr` is always `null` on a freshly created stream — it is derived from the stream's last snapshot, and no snapshot exists yet. It starts returning a value once the stream begins accruing. See [Live APR vs snapshot APR](/sdk/streams/get-streams#live-apr-vs-snapshot-apr).
## Response Fields
Status message describing the creation path used.
On-chain creation payload for token-based streams. Submit it to the corresponding `StreamFactory` on `txParams.chainId`. `null` for point-based streams.
Chain where the stream-factory transaction must be submitted.
Wallet expected to submit the transaction.
16-byte stream ID encoded as a byte array for the stream factory call.
Reward token contract address.
Streamed amount in decimal-string form to preserve precision.
Creation fee amount in decimal-string form. Charged in the reward token on top of `NetTotalAmount` and pulled by the `StreamFactory` in the same `createStream` call. The default fee is **1.5%** of the reward budget; Turtle Pro organizations are exempt (`0`). Point streams also return `0`.
Unix timestamp deadline for the signed payload.
EIP-712 signature bytes serialized as base64 in JSON.
Persisted stream record created by the request. It uses the same public stream schema returned by [Get Streams](/sdk/streams/get-streams).
Persisted adapter configuration array. Each item contains a `type` string and a `params` object.
Reward-token metadata for token-based streams. This uses the same token shape returned by [Get Tokens](/sdk/streams/get-tokens).
## Broadcast the Token-Based Transaction
For token-based streams, the backend does not return a fully serialized raw transaction. Instead, it returns a signed authorization payload in `txParams` that your wallet must use to call `createStream` on the `StreamFactory` for the target chain.
The wallet that sends the transaction must:
* match `txParams.sender`
* be connected to `txParams.chainId`
* approve the `StreamFactory` to transfer the reward token amount needed for `NetTotalAmount + FeeAmount`
### `StreamFactory` addresses by chain
| `chainId` | Network | `StreamFactory` |
| ---------- | --------- | -------------------------------------------- |
| `1` | Ethereum | `0xf44399a74ee5ddef7fa3d064cf66b011ee4a6cae` |
| `56` | BSC | `0x298d2967588b5c93a137ce1a05d0b8cfffb3c120` |
| `43114` | Avalanche | `0x4559605e3003fda8c059e14af4f16ba9a004335a` |
| `8453` | Base | `0x4559605e3003fda8c059e14af4f16ba9a004335a` |
| `11155111` | Sepolia | `0xdfdff939d728585ce8a2cf2d4166f043d917d8d2` |
### TypeScript example
```typescript theme={null}
import { ethers } from 'ethers';
const STREAM_FACTORY_BY_CHAIN: Record = {
1: '0xf44399a74ee5ddef7fa3d064cf66b011ee4a6cae',
56: '0x298d2967588b5c93a137ce1a05d0b8cfffb3c120',
43114: '0x4559605e3003fda8c059e14af4f16ba9a004335a',
8453: '0x4559605e3003fda8c059e14af4f16ba9a004335a',
11155111: '0xdfdff939d728585ce8a2cf2d4166f043d917d8d2',
};
const ERC20_ABI = [
'function approve(address spender, uint256 amount) external returns (bool)',
];
const STREAM_FACTORY_ABI = [
'function createStream((bytes16 streamId,address rewardToken,uint256 netTotalAmount,uint256 feeAmount) params,uint40 deadline,bytes signature) external returns (address stream)',
];
function byteArrayToBytes16(value: number[]): string {
if (value.length !== 16) {
throw new Error('Expected txParams.params.params.StreamId to contain 16 bytes');
}
return ethers.hexlify(Uint8Array.from(value));
}
function base64ToBytes(value: string): Uint8Array {
return Uint8Array.from(atob(value), (char) => char.charCodeAt(0));
}
const response = await fetch('https://earn.turtle.xyz/v2/streams/', {
method: 'POST',
headers: {
'X-API-Key': process.env.TURTLE_SECRET_KEY!,
'Content-Type': 'application/json',
},
body: JSON.stringify({
walletAddress: '0x1111111111111111111111111111111111111111',
type: 2,
rewardTokenId: '56b0fab0-5c3e-49f6-a0a7-57e38d5ea999',
totalAmount: '2500000000000000000000',
startTimestamp: '2026-03-20T00:00:00Z',
endTimestamp: '2026-04-20T00:00:00Z',
customArgs: {
targetTokenId: '8cc2ed9d-bd59-42fd-9df5-329fa22497b6',
apr: '0.12',
},
adapters: [],
}),
});
const { txParams } = await response.json();
if (!txParams) {
throw new Error('Expected txParams for a token-based stream');
}
const streamFactoryAddress = STREAM_FACTORY_BY_CHAIN[txParams.chainId];
if (!streamFactoryAddress) {
throw new Error(`Unsupported StreamFactory for chainId ${txParams.chainId}`);
}
const provider = new ethers.BrowserProvider(window.ethereum);
await provider.send('eth_requestAccounts', []);
const signer = await provider.getSigner();
const signerAddress = await signer.getAddress();
const connectedChainId = Number((await provider.getNetwork()).chainId);
if (signerAddress.toLowerCase() !== txParams.sender.toLowerCase()) {
throw new Error(`Connected wallet ${signerAddress} does not match txParams.sender ${txParams.sender}`);
}
if (connectedChainId !== txParams.chainId) {
throw new Error(`Connected chain ${connectedChainId} does not match txParams.chainId ${txParams.chainId}`);
}
const requiredAllowance =
BigInt(txParams.params.params.NetTotalAmount) + BigInt(txParams.params.params.FeeAmount);
const rewardToken = new ethers.Contract(
txParams.params.params.RewardToken,
ERC20_ABI,
signer,
);
const approveTx = await rewardToken.approve(streamFactoryAddress, requiredAllowance);
await approveTx.wait();
const streamFactory = new ethers.Contract(
streamFactoryAddress,
STREAM_FACTORY_ABI,
signer,
);
const createStreamTx = await streamFactory.createStream(
{
streamId: byteArrayToBytes16(txParams.params.params.StreamId),
rewardToken: txParams.params.params.RewardToken,
netTotalAmount: txParams.params.params.NetTotalAmount,
feeAmount: txParams.params.params.FeeAmount,
},
txParams.params.deadline,
base64ToBytes(txParams.params.signature),
);
const receipt = await createStreamTx.wait();
console.log('Stream creation tx hash:', receipt?.hash);
```
## Operational Notes
The endpoint does not submit the transaction to the chain. It returns the payload required to finalize creation through the `StreamFactory` contract. See [Broadcast the Token-Based Transaction](#broadcast-the-token-based-transaction) for the chain addresses and a TypeScript example. When the wallet submits that transaction, the configured `totalAmount` is part of the on-chain flow, so the wallet must already hold those funds.
This endpoint requires two things at the same time: a valid `X-API-Key` header and the `organization:incentivize:streams:create` permission on the organization attached to that key. If the organization has not been granted that permission, stream creation will be rejected.
Point-based streams do not require an on-chain deployment step, so `txParams` is `null` and the stream is created directly in Turtle's backend. In that case, the returned `stream` is already confirmed.
For token-based streams, the response already includes a persisted `stream` object, but it is still pending until the wallet broadcasts the returned `txParams` to the `StreamFactory`. Until that happens, fields such as `stream.contractAddress` and `stream.creationConfirmedAt` can remain `null`.
`startTimestamp` and `endTimestamp` must be aligned to 15-minute intervals such as `00:00`, `00:15`, `00:30`, or `00:45` UTC.
`rewardToken` and `pointId` are mutually exclusive. You must specify exactly one of them:
* `rewardTokenId` for token-based streams
* `pointId` for point-based streams
Do not provide both, and do not omit both.
If you are creating a stream with `rewardTokenId`, you do not need a point and must not send `pointId`. Points only apply when the reward source is organization-defined points.
## Error Handling
**Status Code:** 401 Unauthorized
```json theme={null}
{
"error": "Invalid API key"
}
```
**Solution:** Pass a valid `X-API-Key` header.
**Status Code:** 403 Forbidden
```json theme={null}
{
"error": {
"status": "PERMISSION_DENIED",
"error": "permission denied"
}
}
```
**Solution:** Use an API key associated with an organization that has the `organization:incentivize:streams:create` permission.
**Status Code:** 400 Bad Request
```json theme={null}
{
"error": {
"status": "INVALID_ARGUMENT",
"error": "exactly one between RewardToken and PointID must be provided"
}
}
```
**Common causes:**
* unsupported `type`
* invalid `customArgs` for the chosen type
* timestamps not aligned to 15-minute boundaries
* `totalAmount` present for Daily Budget streams
* `walletAddress` or `rewardTokenId` missing for token-based streams
**Status Code:** 500 Internal Server Error
**Solution:** Retry the request and contact Turtle if the issue persists.
# Get Merkle Proofs
Source: https://docs.turtle.xyz/sdk/streams/get-merkle-proofs
Fetch Merkle proofs for a wallet to claim token stream rewards on-chain
This endpoint is **permissionless**. No API key is required. Merkle proofs are public data that anyone can verify on-chain.
## Overview
`GET /v2/streams/merkle_proofs` returns Merkle proofs for a wallet across one or more token streams. Each proof contains everything needed to call `claim()` on the stream's smart contract: the cumulative allocation amount, the proof array, the contract address, and the chain ID.
Use this endpoint when building a claim UI on a partner website or in any frontend that needs to submit on-chain claim transactions.
This endpoint returns proofs for **token-based streams only**. Point-based streams do not have on-chain Merkle trees.
## Endpoint
```bash curl theme={null}
curl -X GET "https://earn.turtle.xyz/v2/streams/merkle_proofs?wallet=0x...&streamIds=7e9c407e-3992-4587-b8e7-9a30f96b12b5"
```
```typescript TypeScript theme={null}
const wallet = '0x...';
const streamId = '7e9c407e-3992-4587-b8e7-9a30f96b12b5';
const response = await fetch(
`https://earn.turtle.xyz/v2/streams/merkle_proofs?wallet=${wallet}&streamIds=${streamId}`
);
const data = await response.json();
```
To query multiple streams, repeat the `streamIds` parameter:
```bash curl theme={null}
curl -X GET "https://earn.turtle.xyz/v2/streams/merkle_proofs?wallet=0x...&streamIds=7e9c407e-3992-4587-b8e7-9a30f96b12b5&streamIds=6ab3c09e-a384-436e-ba8b-c30d249bdf83"
```
```typescript TypeScript theme={null}
const wallet = '0x...';
const streamIds = [
'7e9c407e-3992-4587-b8e7-9a30f96b12b5',
'6ab3c09e-a384-436e-ba8b-c30d249bdf83',
];
const params = new URLSearchParams({ wallet });
streamIds.forEach((id) => params.append('streamIds', id));
const response = await fetch(
`https://earn.turtle.xyz/v2/streams/merkle_proofs?${params}`
);
const data = await response.json();
```
**Query Parameters**
The user's EVM wallet address.
One or more stream UUIDs to fetch proofs for. Repeat the parameter for multiple streams. You can find your stream IDs via [Get Streams](/sdk/streams/get-streams) or from your Turtle dashboard.
## Response Example
```json theme={null}
{
"proofs": [
{
"streamId": "7e9c407e-3992-4587-b8e7-9a30f96b12b5",
"chainId": 8453,
"contractAddress": "0x...",
"amount": "1500000000000000000000",
"proof": [
"0xabc123...",
"0xdef456...",
"0x789012..."
],
"rootHash": "0x...",
"timestamp": "2026-05-20T13:05:10Z"
}
]
}
```
## Claim parameters
The response includes everything needed to call `claim()` on-chain. Three fields map directly to the contract's parameters:
| Response field | Contract parameter | Notes |
| -------------- | ----------------------- | ------------------------------------------- |
| `amount` | `uint256 amount` | Pass as-is (raw token units) |
| `timestamp` | `uint40 timestamp` | Convert from ISO 8601 to Unix epoch seconds |
| `proof` | `bytes32[] merkleProof` | Pass as-is |
The `timestamp` identifies which Merkle root the proof was generated against. The contract validates the proof against that root. If the timestamp doesn't match a committed root, the transaction reverts. See [Claim Rewards](/sdk/streams/claim-rewards) for the full integration guide.
## Response Fields
Array of Merkle proofs, one per requested stream where the wallet has an allocation.
### `StreamMerkleProof`
The stream this proof belongs to.
Decimal EVM chain ID where the stream contract is deployed (e.g. `8453` for Base, `1` for Ethereum).
The stream contract address to call `claim()` on.
Total cumulative allocation in raw token units. This is the **total ever allocated** to the wallet, not the unclaimed balance. The contract tracks what has already been claimed. Call `getRewardToken()` on the stream contract to look up the token's decimals for display formatting.
ISO 8601 timestamp of the Merkle root this proof was generated against. Required for the `claim()` call. The contract uses it to look up the correct root hash for verification. Must be converted to Unix epoch seconds (`uint40`) before passing to the contract.
Array of `bytes32` hashes for Merkle verification, passed directly to the contract's `claim()` function.
The Merkle root hash this proof was generated against. Informational only; the contract resolves the root from the `timestamp` parameter, so you don't need to pass this on-chain.
## Operational Notes
The `amount` field is cumulative. It represents the wallet's total allocation across all snapshots, not a per-snapshot delta. The on-chain contract tracks how much has already been claimed and releases the difference when `claim()` is called.
Proofs are recomputed on each snapshot cycle. Between snapshots, the same proof data is returned. There is no need to poll this endpoint. Fetch once when the user is ready to claim.
If the wallet has no allocation in any of the requested streams, the `proofs` array will be empty. This is not an error. It means the wallet is not a participant in those streams.
Pass `amount`, `timestamp`, and `proof` directly to the stream contract's `claim()` function. See [Claim Rewards](/sdk/streams/claim-rewards) for the full on-chain integration guide.
## Error Handling
**Status Code:** 400 Bad Request
```json theme={null}
{
"error": "wallet and streamIds are required"
}
```
**Solution:** Ensure both `wallet` and at least one `streamIds` parameter are present.
**Status Code:** 500 Internal Server Error
**Solution:** Retry the request and contact Turtle if the issue persists.
# Get Points
Source: https://docs.turtle.xyz/sdk/streams/get-points
Retrieve points, optionally filtered by organization ID, symbol, or name
## Overview
`GET /v2/streams/points` returns points. This is a public endpoint — no API key is required.
Use `orgId` to narrow results to a specific organization. This endpoint is useful when your integration supports point-based streams and needs to list the point assets available for stream creation or reporting.
If your organization only creates token-based streams with `rewardToken`, you do not need to call this endpoint.
## Endpoint
```bash curl theme={null}
curl -X GET "https://earn.turtle.xyz/v2/streams/points?symbol=PTS"
```
```typescript TypeScript theme={null}
const response = await fetch(
'https://earn.turtle.xyz/v2/streams/points?symbol=PTS'
);
const data = await response.json();
```
**Query Parameters**
Optional point identifier.
Optional organization identifier. When provided, returns only points belonging to that organization.
Optional point symbol filter.
Optional point name filter.
## Response Example
```json theme={null}
{
"points": [
{
"id": "7ff13cf6-53d0-4f3e-bd1a-e8eab6db4cf1",
"orgId": "9f51b66a-d13a-4b55-8515-ae6e4ef7cf25",
"symbol": "PTS",
"name": "Partner Points",
"decimals": 18,
"logoUrl": "https://cdn.example.com/points/pts.png",
"createdAt": "2026-03-01T00:00:00Z",
"updatedAt": "2026-03-01T00:00:00Z"
}
]
}
```
## Response Fields
Array of points matching the provided filters.
See [Create Point](/sdk/streams/create-point) for the full `Point` schema.
## Important Notes
Points are used when creating streams that use `pointId` as the reward source. They are not required for streams that use `rewardToken`.
You can query by `id`, `orgId`, `symbol`, `name`, or any combination supported by your integration needs.
## Error Handling
**Status Code:** 500 Internal Server Error
**Solution:** Retry the request and contact Turtle if the issue persists.
# Get Streams
Source: https://docs.turtle.xyz/sdk/streams/get-streams
Retrieve confirmed streams, optionally filtered by stream ID or organization ID
## Overview
`GET /v2/streams/` returns confirmed streams. This is a public endpoint — no API key is required.
* If no query parameters are sent, the endpoint returns all confirmed streams.
* Use `id` to retrieve a specific stream by its UUID.
* Use `orgId` to filter results to streams belonging to a specific organization.
This endpoint is intended for backoffice dashboards, reporting tools, campaign managers, and partner integrations that need to inspect stream configurations.
To display the rate a stream is **currently** distributing, read `estimatedLiveApr` — not `lastSnapshot.apr`. `lastSnapshot.apr` is a historical value tied to its own snapshot timestamp and stays populated forever after a stream is paused or ends. See [Live APR vs snapshot APR](#live-apr-vs-snapshot-apr).
## Endpoint
### Get all streams
```bash curl theme={null}
curl -X GET "https://earn.turtle.xyz/v2/streams/?withSnapshots=false&usersCount=false"
```
```typescript TypeScript theme={null}
const response = await fetch(
'https://earn.turtle.xyz/v2/streams/?withSnapshots=false&usersCount=false'
);
const data = await response.json();
```
### Get streams filtered by organization
```bash curl theme={null}
curl -X GET "https://earn.turtle.xyz/v2/streams/?orgId=9f51b66a-d13a-4b55-8515-ae6e4ef7cf25"
```
```typescript TypeScript theme={null}
const orgId = '9f51b66a-d13a-4b55-8515-ae6e4ef7cf25';
const response = await fetch(
`https://earn.turtle.xyz/v2/streams/?orgId=${orgId}`
);
const data = await response.json();
```
### Get one stream by ID
```bash curl theme={null}
curl -X GET "https://earn.turtle.xyz/v2/streams/?id=550e8400-e29b-41d4-a716-446655440000&withSnapshots=true&usersCount=true"
```
```typescript TypeScript theme={null}
const streamId = '550e8400-e29b-41d4-a716-446655440000';
const response = await fetch(
`https://earn.turtle.xyz/v2/streams/?id=${streamId}&withSnapshots=true&usersCount=true`
);
const data = await response.json();
```
**Query Parameters**
Optional stream identifier. When provided, the endpoint filters the result set to that stream ID.
Optional organization identifier. When provided, the endpoint returns only streams belonging to that organization.
Include the full historical `snapshots` array for each returned stream.
Add `userCount` and `activeUserCount` to each included snapshot object.
## Response Example
```json theme={null}
{
"streams": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"chainId": 1,
"contractAddress": "0x4C6F5a1aA2B9985d4A8b9189C2118E7f55E2f701",
"userId": null,
"orgId": "9f51b66a-d13a-4b55-8515-ae6e4ef7cf25",
"admin": "0x1111111111111111111111111111111111111111",
"type": 2,
"createdAt": "2026-03-10T12:00:00Z",
"updatedAt": "2026-03-10T12:15:00Z",
"startTimestamp": "2026-03-11T00:00:00Z",
"endTimestamp": "2026-04-11T00:00:00Z",
"totalAmount": "2500000000000000000000",
"creationConfirmedAt": "2026-03-10T12:04:32Z",
"snapshotComputationPaused": false,
"merkleTreeComputationPaused": true,
"hashCommitmentPaused": true,
"claimPaused": true,
"customArgs": {
"targetTokenId": "8cc2ed9d-bd59-42fd-9df5-329fa22497b6",
"apr": "0.12",
"targetToken": {
"id": "8cc2ed9d-bd59-42fd-9df5-329fa22497b6",
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"name": "USD Coin",
"symbol": "USDC",
"decimals": 6,
"isNative": false,
"logoUrl": "https://...",
"chain": {
"id": "f4c8c3d9-6ae5-4dfa-8d33-7d7bb0a9e73c",
"name": "Ethereum",
"slug": "ethereum",
"chainId": "1",
"isTestnet": false,
"logoUrl": "https://...",
"ecosystem": "evm",
"status": "active",
"explorerUrl": "https://etherscan.io"
},
"active": true,
"priceUsd": 1,
"canonicalAssetId": "f4a35f17-7482-4d93-bc75-2ebd4f483d22",
"streamsMinAmount": "1000000",
"totalTurtleTvl": 10234567.12
}
},
"adapters": [],
"point": null,
"strategy": "Fixed APR",
"lastSnapshot": {
"timestamp": "2026-03-11T00:00:00Z",
"amountDistributed": "8123456789012345678",
"amountBase": "8123456789012345678",
"rootHash": null,
"commitTxHash": null,
"createdAt": "2026-03-11T00:01:00Z",
"updatedAt": "2026-03-11T00:01:00Z",
"tvl": "152340.12",
"baseTvl": "152340.12",
"baseApr": "0.105",
"apr": "0.12",
"rewardTokenPrice": "1.00",
"customMetrics": {},
"customArgs": {},
"userCount": 124,
"activeUserCount": 118
},
"committedSnapshot": null,
"snapshots": [],
"rewardToken": {
"id": "56b0fab0-5c3e-49f6-a0a7-57e38d5ea999",
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"name": "USD Coin",
"symbol": "USDC",
"decimals": 6,
"chainId": 1,
"logoUrl": "https://...",
"isAllowedRewardToken": true
},
"estimatedLiveApr": "0.12"
}
]
}
```
## Response Semantics
If you omit all query parameters, the endpoint returns all confirmed streams across all organizations.
If you send `id`, the endpoint still returns a `streams` array. The array will contain either one matching stream or be empty if no stream with that ID exists.
If you send `orgId`, only streams belonging to that organization are returned. You can combine `orgId` with `id` to look up a specific stream within a specific organization.
## Live APR vs snapshot APR
The response exposes two different APR values, and they answer two different questions.
| Field | What it means | When to use it |
| ------------------ | ---------------------------------------------------------------------------------------------- | --------------------------------------------- |
| `estimatedLiveApr` | The rate the stream is currently distributing. Only set while the stream is actively accruing. | Anywhere you show a stream's present rate. |
| `lastSnapshot.apr` | The APR computed *for that snapshot*, valid as of `lastSnapshot.timestamp`. | Historical reporting, charts, reconciliation. |
A paused or ended stream keeps its last snapshot indefinitely, so `lastSnapshot.apr` keeps returning the stream's final rate long after it stopped distributing. Reading it as the current rate is the mistake `estimatedLiveApr` exists to prevent.
`estimatedLiveApr` is sourced from `lastSnapshot.apr` and is `null` when any of these hold:
* the stream has no snapshot yet, or the last snapshot has no `apr` — for example, point-based streams;
* `snapshotComputationPaused` is `true`;
* the stream has ended — `endTimestamp` is in the past;
* `lastSnapshot.timestamp` is more than 24 hours old.
The 24-hour bound exists because snapshots accrue every 12 hours, so it tolerates one missed accrual run before the live estimate is withdrawn.
## Stream Fields
The response body contains a `streams` array. Each item in that array is a `Stream` object with the fields described below.
```typescript theme={null}
streams: Stream[]
```
List of confirmed streams matching the provided filters.
### `Stream`
Unique stream identifier.
Decimal EVM chain ID for on-chain streams. `null` for point-based streams that do not deploy a contract.
Deployed on-chain stream contract address when available. It can be `null` for point-based streams or token-based streams that are still pending confirmation.
Optional user identifier associated with the stream when present.
Organization that owns the stream.
Admin EVM address for the stream when applicable.
Stream type. Supported values are `1` (`Fixed Rate`), `2` (`Fixed APR`), `3` (`Daily Budget`), `4` (`Airdrop`), and `5` (`Yield Match`).
Timestamp when the stream record was created in Turtle's backend.
Timestamp of the most recent update to the stream record.
UTC start time for the stream.
UTC end time for the stream when configured.
Total reward amount in base units when applicable.
Confirmation timestamp for stream creation. It can be `null` while a token-based stream is still pending on-chain creation.
Whether snapshot computation is paused for the stream.
Whether merkle tree computation is paused for the stream.
Whether hash commitment updates are paused for the stream.
Whether claiming rewards is currently paused for the stream.
Strategy-specific configuration object for the stream.
Persisted adapter configuration array. Each adapter item contains a `type` string and a `params` object.
Point metadata when the stream uses a point-based reward source. `null` for token-based streams.
Human-readable strategy name for the stream.
Most recent snapshot computed for the stream, if one exists.
Most recent committed snapshot for the stream, if one exists.
Full snapshot history when `withSnapshots=true`. Otherwise this field can be empty or omitted.
Reward-token metadata for token-based streams. This uses the public `SupportedToken` shape from [Get Tokens](/sdk/streams/get-tokens).
Estimated APR the stream is **currently** distributing, expressed as a decimal fraction — multiply by 100 for the percentage (for example, `0.12` means 12%).
Use this field, not `lastSnapshot.apr`, whenever you display a stream's current rate. It is sourced from `lastSnapshot.apr` but only returned while the stream is actively accruing: it is `null` when the stream has no snapshot APR, when `snapshotComputationPaused` is `true`, when the stream has ended, or when `lastSnapshot.timestamp` is more than 24 hours old. A `null` value means no live rate is available — it does not mean 0%. See [Live APR vs snapshot APR](#live-apr-vs-snapshot-apr).
### `AdapterConfig`
Adapter type identifier.
Adapter-specific configuration object.
### `Point`
See [Get Points](/sdk/streams/get-points) for the full `Point` schema and examples.
### `StreamSnapshot`
APR-related snapshot fields are only populated for token-based streams. For point-based streams, `baseApr`, `apr`, and `rewardTokenPrice` are omitted from the snapshot.
Snapshot timestamp.
Amount distributed in the snapshot, encoded as a decimal string.
Base amount used for the snapshot, encoded as a decimal string.
Merkle root hash when the snapshot has one.
Transaction hash of the commit operation when available.
Timestamp when the snapshot record was created.
Timestamp of the latest update to the snapshot record.
Total value locked at snapshot time when available.
Base TVL at snapshot time when available.
Base APR computed for the snapshot before adapter adjustments, expressed as a decimal fraction — multiply by 100 for the percentage (for example, `0.05` means 5%). This is only populated for token-based streams.
Effective APR computed for the snapshot after adapter adjustments, expressed as a decimal fraction — multiply by 100 for the percentage (for example, `0.05` means 5%). This is only populated for token-based streams.
This is a historical value, valid as of `timestamp`. On `lastSnapshot` it keeps returning the stream's final rate after the stream is paused or ends, so do not treat it as the current rate — use the stream-level `estimatedLiveApr` for that.
Time-weighted-average (TWA) USD price of the reward token across the snapshot interval. This is only populated for token-based streams.
Snapshot-specific computed metrics.
Snapshot-specific custom arguments.
Number of users represented in the snapshot when `usersCount=true`.
Number of active users represented in the snapshot when `usersCount=true`.
## Error Handling
**Status Code:** 500 Internal Server Error
**Solution:** Retry the request and contact Turtle if the issue persists.
# Get Streams for Wallet
Source: https://docs.turtle.xyz/sdk/streams/get-streams-for-wallet
Retrieve all streams a wallet has participated in, with snapshot data per stream
## Overview
`GET /v2/streams/wallets/{address}` returns all streams a given wallet address has snapshot data in, together with the wallet's snapshot history for each stream. This is a public endpoint — no API key is required.
By default the endpoint returns only the latest snapshot per stream, which is efficient for summary views. Pass `withSnapshots=true` to include the full historical timeline for every stream.
Use `withSnapshots=false` (the default) for portfolio overviews and summary widgets. Use `withSnapshots=true` when you need the full reward history across all streams for a wallet, such as for charts or reconciliation workflows.
## Endpoint
```bash curl theme={null}
# Latest snapshot per stream (default)
curl -X GET "https://earn.turtle.xyz/v2/streams/wallets/0x1111111111111111111111111111111111111111"
# Full snapshot history per stream
curl -X GET "https://earn.turtle.xyz/v2/streams/wallets/0x1111111111111111111111111111111111111111?withSnapshots=true"
```
```typescript TypeScript theme={null}
const walletAddress = '0x1111111111111111111111111111111111111111';
// Latest snapshot per stream (default)
const response = await fetch(
`https://earn.turtle.xyz/v2/streams/wallets/${walletAddress}`
);
// Full snapshot history per stream
const responseWithHistory = await fetch(
`https://earn.turtle.xyz/v2/streams/wallets/${walletAddress}?withSnapshots=true`
);
const data = await response.json();
```
## Parameters
**Path Parameters**
EVM wallet address to look up, such as `0x1111111111111111111111111111111111111111`. The backend resolves the address against stored wallet snapshot records across all streams.
**Query Parameters**
Controls how much snapshot history is returned per stream.
* `false` (default) — each stream entry contains a single-element `snapshots` array with the most recent snapshot only. Use this for summary tables and portfolio cards.
* `true` — each stream entry contains the full `snapshots` array with every recorded snapshot. Use this for historical charts, cumulative reward plots, and reconciliation.
## Response Example
```json withSnapshots=false (default) theme={null}
{
"streams": [
{
"streamId": "550e8400-e29b-41d4-a716-446655440000",
"userAddress": "0x1111111111111111111111111111111111111111",
"snapshots": [
{
"timestamp": "2026-03-21T00:00:00Z",
"rewardsAccumulated": "8345000000000000000",
"rewardsAccumulatedBase": "8345000000000000000",
"createdAt": "2026-03-21T00:05:00Z",
"updatedAt": "2026-03-21T00:05:00Z",
"tvl": "152340.12",
"baseTvl": "152340.12",
"baseApr": "0.105",
"apr": "0.12",
"customMetrics": { "source": "vault-balance" }
}
],
"stream": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"chainId": 1,
"strategy": "Fixed APR",
"totalAmount": "2500000000000000000000",
"rewardToken": {
"symbol": "USDC",
"decimals": 6
},
"estimatedLiveApr": "0.12"
}
}
]
}
```
```json withSnapshots=true theme={null}
{
"streams": [
{
"streamId": "550e8400-e29b-41d4-a716-446655440000",
"userAddress": "0x1111111111111111111111111111111111111111",
"snapshots": [
{
"timestamp": "2026-03-19T00:00:00Z",
"rewardsAccumulated": "1000000000000000000",
"rewardsAccumulatedBase": "1000000000000000000",
"createdAt": "2026-03-19T00:05:00Z",
"updatedAt": "2026-03-19T00:05:00Z",
"tvl": "80000.12",
"baseTvl": "80000.12",
"baseApr": "0.105",
"apr": "0.12",
"customMetrics": { "source": "vault-balance" }
},
{
"timestamp": "2026-03-20T00:00:00Z",
"rewardsAccumulated": "4500000000000000000",
"rewardsAccumulatedBase": "4500000000000000000",
"createdAt": "2026-03-20T00:05:00Z",
"updatedAt": "2026-03-20T00:05:00Z",
"tvl": "120340.66",
"baseTvl": "120340.66",
"baseApr": "0.105",
"apr": "0.12",
"customMetrics": { "source": "vault-balance" }
},
{
"timestamp": "2026-03-21T00:00:00Z",
"rewardsAccumulated": "8345000000000000000",
"rewardsAccumulatedBase": "8345000000000000000",
"createdAt": "2026-03-21T00:05:00Z",
"updatedAt": "2026-03-21T00:05:00Z",
"tvl": "152340.12",
"baseTvl": "152340.12",
"baseApr": "0.105",
"apr": "0.12",
"customMetrics": { "source": "vault-balance" }
}
],
"stream": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"chainId": 1,
"strategy": "Fixed APR",
"totalAmount": "2500000000000000000000",
"rewardToken": {
"symbol": "USDC",
"decimals": 6
},
"estimatedLiveApr": "0.12"
}
}
]
}
```
## Response Semantics
When `withSnapshots=false`, each stream entry's `snapshots` array always contains exactly one element — the most recent snapshot recorded for that wallet in that stream. This is equivalent to the `lastSnapshot` field returned by [Get Stream Wallets](/sdk/streams/get-wallets), but embedded in an array for a consistent shape regardless of the flag.
When `withSnapshots=true`, the `snapshots` array contains every recorded snapshot for the wallet in that stream, ordered by timestamp descending. The first element is always the most recent. This is the same data returned by [Get Wallet Data](/sdk/streams/get-wallet) but across all streams in a single response.
If the wallet address has no snapshot data in any stream, the endpoint returns `streams: []` rather than failing. This means the wallet has not participated in any confirmed stream yet.
The response only includes streams whose on-chain creation has been confirmed. Streams in a pending creation state are not returned even if internal records already exist.
Additionally, soft-deleted streams are always excluded — even if the wallet accumulated snapshot data in them before deletion. This means a wallet's historical snapshots for a deleted stream will never appear in this response.
## Response Fields
```typescript theme={null}
streams: WalletData[]
```
List of streams the wallet has participated in, one entry per stream.
### `WalletData`
Identifier of the stream. This duplicates the `stream.id` field for convenience.
The wallet address whose data is being returned. Mirrors the `address` path parameter.
Snapshot history for this wallet in the stream. Contains one element when `withSnapshots=false` (the latest only), or the full timeline when `withSnapshots=true`. Ordered by timestamp descending. For the canonical `WalletSnapshot` field definitions, see the `WalletSnapshot` section on the [Get Stream Wallets](/sdk/streams/get-wallets) page.
Full stream object. Uses the same `Stream` schema returned by [Get Streams](/sdk/streams/get-streams), including `id`, `chainId`, `contractAddress`, `customArgs`, `lastSnapshot`, `committedSnapshot`, `point`, `rewardToken`, and `estimatedLiveApr`.
### `WalletSnapshot`
APR-related fields are only populated for token-based streams. For point-based streams, `baseApr` and `apr` are omitted.
Effective timestamp of the snapshot — the time bucket the metrics correspond to, not the database write time.
Total rewards accumulated by the wallet at this snapshot, in base units (wei for token streams, point precision for point streams). Reflects post-adapter values.
Accumulated rewards before adapter adjustments are applied.
Timestamp when this snapshot row was first created in Turtle's backend.
Timestamp of the latest update applied to this snapshot row.
Time-weighted-average (TWA) USD TVL for the wallet after adapters.
TWA USD TVL for the wallet before adapters.
Base APR before adapter adjustments, expressed as a decimal fraction — multiply by 100 for the percentage (for example, `0.05` means 5%). Only populated for token-based streams.
Effective APR after adapter adjustments, expressed as a decimal fraction — multiply by 100 for the percentage (for example, `0.05` means 5%). Only populated for token-based streams.
Strategy-specific metrics for the snapshot. Treat as extensible JSON.
### `Stream`
The `stream` field uses the same `Stream` schema returned by [Get Streams](/sdk/streams/get-streams). See that page for the complete field reference, including `lastSnapshot`, `committedSnapshot`, `rewardToken`, `point`, `customArgs`, and `estimatedLiveApr`.
To show the rate the wallet's stream is currently paying, read `stream.estimatedLiveApr` rather than `stream.lastSnapshot.apr` or the wallet's own snapshot `apr` — those are historical values tied to their snapshot timestamps. See [Live APR vs snapshot APR](/sdk/streams/get-streams#live-apr-vs-snapshot-apr).
## Integration Notes
Use `withSnapshots=false` (the default) for any view that only needs the current state: portfolio cards, leaderboards, summary widgets. Use `withSnapshots=true` only when you need to chart or reconcile the full reward history — it returns significantly more data per stream.
Reward amounts are serialized as strings to avoid precision loss in JavaScript environments. Keep them as strings in transit and use a big-number library only when arithmetic or unit conversion is needed.
If you need snapshot data for one wallet within a specific stream, use [Get Wallet Data](/sdk/streams/get-wallet). If you need a paginated list of all wallets for one stream, use [Get Stream Wallets](/sdk/streams/get-wallets).
## Error Handling
**Status Code:** 500 Internal Server Error
**Solution:** Retry the request and contact Turtle if the issue persists.
# Get Tokens
Source: https://docs.turtle.xyz/sdk/streams/get-tokens
Retrieve supported tokens for targetTokenId and rewardTokenId selection on a specific chain
## Overview
`GET /v2/streams/tokens` returns the active tokens supported for stream creation on a specific chain. This is a public endpoint — no API key is required.
Use this endpoint in two different ways:
* To resolve the tokens that can be used as `targetTokenId` inside stream `customArgs`.
* To resolve the tokens that can be used as `rewardTokenId` for token-based streams.
For reward-token selection, use the tokens where `isAllowedRewardToken` is `true`.
The `chainId` query parameter for this endpoint is the decimal EVM chain ID.
## Supported Chains by Use Case
### `targetTokenId` chains
For `targetTokenId`, this endpoint can be queried with any of the following decimal chain IDs.
#### Mainnet
| Chain | Decimal chainId |
| --------------- | --------------- |
| `Abstract` | `2741` |
| `Arbitrum` | `42161` |
| `Avalanche` | `43114` |
| `Base` | `8453` |
| `BeraChain` | `80094` |
| `Blast` | `81457` |
| `BSC` | `56` |
| `Ethereum` | `1` |
| `Fraxtal` | `238` |
| `Gnosis` | `100` |
| `HyperEVM` | `999` |
| `Ink` | `57073` |
| `Katana` | `747474` |
| `Linea` | `59144` |
| `Linea-Sepolia` | `59141` |
| `Manta` | `169` |
| `Mantle` | `5000` |
| `Metis` | `1088` |
| `Mezo` | `31612` |
| `Mode Network` | `34443` |
| `Monad` | `143` |
| `Optimism` | `10` |
| `Peaq` | `3338` |
| `Plasma` | `9745` |
| `Polygon` | `137` |
| `Polygon zkEVM` | `1101` |
| `Scroll` | `534352` |
| `Sonic` | `146` |
| `Swell` | `1923` |
| `TAC` | `239` |
| `Unichain` | `130` |
| `Worldchain` | `480` |
| `XLayer` | `196` |
| `Zircuit` | `48900` |
| `ZkSync` | `324` |
#### Testnet
| Chain | Decimal chainId |
| --------------- | --------------- |
| `Sepolia` | `11155111` |
| `Linea-Sepolia` | `59141` |
### `rewardToken` chains
This same endpoint is also used for `rewardToken`, but stream creation currently supports `rewardToken` only on these 5 networks:
#### Mainnet
| Chain | Decimal chainId |
| ----------- | --------------- |
| `Ethereum` | `1` |
| `Base` | `8453` |
| `Avalanche` | `43114` |
| `BSC` | `56` |
#### Testnet
| Chain | Decimal chainId |
| --------- | --------------- |
| `Sepolia` | `11155111` |
Sepolia is included here specifically so you can test stream creation with `rewardToken` before moving to mainnet.
If you need TURTLE test tokens on Sepolia (`0xa78559593289728719bc46e7559ebdee5bc5ef7a`) for testing, please contact the Turtle team to request them.
On any of those supported networks, a stream can use both values on the same chain: a `rewardToken` for the reward asset and a `targetTokenId` inside `customArgs` for the tracked target token. The difference is not that they must belong to different chains. The difference is that `rewardToken` is currently limited to this smaller subset, while `targetTokenId` supports the broader list above.
## Endpoint
```bash curl theme={null}
curl -X GET "https://earn.turtle.xyz/v2/streams/tokens?chainId=1"
```
```typescript TypeScript theme={null}
const chainId = 1;
const response = await fetch(
`https://earn.turtle.xyz/v2/streams/tokens?chainId=${chainId}`
);
const data = await response.json();
```
**Query Parameters**
Decimal EVM chain ID. This is required. Use the decimal `chainId` values listed above.
## Response Example
```json theme={null}
{
"tokens": [
{
"id": "56b0fab0-5c3e-49f6-a0a7-57e38d5ea999",
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"name": "USD Coin",
"symbol": "USDC",
"decimals": 6,
"chainId": 1,
"logoUrl": "https://cdn.example.com/tokens/usdc.png",
"isAllowedRewardToken": true
},
{
"id": "9f6ef77b-3ea5-4d2c-8d64-91e9e4c8b123",
"address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"name": "Tether USD",
"symbol": "USDT",
"decimals": 6,
"chainId": 1,
"logoUrl": "https://cdn.example.com/tokens/usdt.png",
"isAllowedRewardToken": false
}
]
}
```
## Response Fields
```typescript theme={null}
tokens: SupportedToken[]
```
List of active tokens that can be used for streams on the requested chain.
### `SupportedToken` fields
Unique token identifier in Turtle's config catalog.
Token contract address.
Token name.
Token symbol.
Decimal precision used by the token.
Decimal EVM chain ID for the token.
Token logo URL.
Whether the token can be used as `rewardTokenId` for token-based stream creation on that chain.
## Important Notes
Requests without `chainId`, or with `chainId = 0`, are rejected with `400 Invalid Argument`.
The handler excludes inactive tokens and filters out native assets, so this endpoint returns the currently usable non-native token set for stream creation.
A stream can use both a `rewardToken` and a `targetTokenId` on the same supported network. The distinction here is support scope, not mutual exclusion: `rewardToken` is currently limited to the 5-chain subset listed above, while `targetTokenId` supports the broader chain list documented on this page.
When selecting a `rewardTokenId` for `POST /v2/streams/`, choose one of the returned tokens where `isAllowedRewardToken` is `true`. Tokens with `isAllowedRewardToken = false` can still be valid for other use cases such as `targetTokenId`, but not as the stream reward token.
When calling this endpoint, send the decimal EVM `chainId` shown in the tables above.
## Error Handling
**Status Code:** 400 Bad Request
```json theme={null}
{
"error": {
"status": "INVALID_ARGUMENT",
"error": "chainId is required"
}
}
```
**Solution:** Send a valid decimal EVM chain ID in the `chainId` query parameter.
**Status Code:** 500 Internal Server Error
**Solution:** Retry the request and contact Turtle if the issue persists.
# Get Wallet Data
Source: https://docs.turtle.xyz/sdk/streams/get-wallet
Retrieve all snapshots accumulated by one wallet in a specific stream, together with the parent stream object
## Overview
`GET /v2/streams/{id}/wallets/{address}` returns the full snapshot history for one wallet inside one stream. This is a public endpoint — no API key is required.
Use this endpoint when you need a wallet-level drilldown: detailed reward history, charting, reconciliation, user support tooling, or a per-wallet export that includes every available snapshot instead of just the most recent one.
The response includes both the wallet history and the parent `stream` object. This lets you render a wallet-detail page without making an extra call to the streams listing endpoint.
## Endpoint
```bash curl theme={null}
curl -X GET "https://earn.turtle.xyz/v2/streams/550e8400-e29b-41d4-a716-446655440000/wallets/0x1111111111111111111111111111111111111111"
```
```typescript TypeScript theme={null}
const streamId = '550e8400-e29b-41d4-a716-446655440000';
const walletAddress = '0x1111111111111111111111111111111111111111';
const response = await fetch(
`https://earn.turtle.xyz/v2/streams/${streamId}/wallets/${walletAddress}`
);
const data = await response.json();
```
## Parameters
**Path Parameters**
Stream identifier. This selects the stream whose wallet history you want to inspect.
Wallet address to inspect within the selected stream. This should be the EVM address whose snapshot history you want to retrieve. Use a standard hex address such as `0x1111111111111111111111111111111111111111`; checksummed addresses are recommended for readability, although the backend ultimately resolves the address value against stored wallet records.
## Response Example
```json theme={null}
{
"wallet": {
"streamId": "550e8400-e29b-41d4-a716-446655440000",
"userAddress": "0x1111111111111111111111111111111111111111",
"snapshots": [
{
"timestamp": "2026-03-19T00:00:00Z",
"rewardsAccumulated": "1000000000000000000",
"rewardsAccumulatedBase": "1000000000000000000",
"createdAt": "2026-03-19T00:05:00Z",
"updatedAt": "2026-03-19T00:05:00Z",
"tvl": "80000.12",
"baseTvl": "80000.12",
"baseApr": "0.105",
"apr": "0.12",
"customMetrics": {
"source": "vault-balance"
}
},
{
"timestamp": "2026-03-20T00:00:00Z",
"rewardsAccumulated": "2150000000000000000",
"rewardsAccumulatedBase": "2150000000000000000",
"createdAt": "2026-03-20T00:05:00Z",
"updatedAt": "2026-03-20T00:05:00Z",
"tvl": "120340.66",
"baseTvl": "120340.66",
"baseApr": "0.105",
"apr": "0.12",
"customMetrics": {
"source": "vault-balance"
}
}
],
"stream": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"chainId": 1,
"contractAddress": "0x4C6F5a1aA2B9985d4A8b9189C2118E7f55E2f701",
"userId": null,
"orgId": "9f51b66a-d13a-4b55-8515-ae6e4ef7cf25",
"admin": "0x1111111111111111111111111111111111111111",
"type": 2,
"createdAt": "2026-03-10T12:00:00Z",
"updatedAt": "2026-03-10T12:15:00Z",
"startTimestamp": "2026-03-11T00:00:00Z",
"endTimestamp": "2026-04-11T00:00:00Z",
"totalAmount": "2500000000000000000000",
"creationConfirmedAt": "2026-03-10T12:04:32Z",
"snapshotComputationPaused": false,
"merkleTreeComputationPaused": false,
"hashCommitmentPaused": false,
"claimPaused": false,
"customArgs": {
"targetTokenId": "8cc2ed9d-bd59-42fd-9df5-329fa22497b6",
"apr": "0.12"
},
"adapters": [],
"point": null,
"strategy": "Fixed APR",
"lastSnapshot": {
"timestamp": "2026-03-20T00:00:00Z",
"amountDistributed": "8123456789012345678",
"amountBase": "8123456789012345678",
"rootHash": null,
"commitTxHash": null,
"createdAt": "2026-03-20T00:01:00Z",
"updatedAt": "2026-03-20T00:01:00Z",
"tvl": "152340.12",
"baseTvl": "152340.12",
"baseApr": "0.105",
"apr": "0.12",
"rewardTokenPrice": "1.00",
"customMetrics": {},
"customArgs": {}
},
"committedSnapshot": null,
"rewardToken": {
"id": "56b0fab0-5c3e-49f6-a0a7-57e38d5ea999",
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"name": "USD Coin",
"symbol": "USDC",
"decimals": 6,
"chainId": 1,
"logoUrl": "https://cdn.example.com/tokens/usdc.png",
"isAllowedRewardToken": true
}
}
}
}
```
## Response Semantics
Unlike the list-wallets endpoint, this response includes the full `snapshots` array available for the requested wallet in the selected stream.
If the stream exists but the requested address has no stored snapshots in that stream, the endpoint returns `404 Not Found`.
The `wallet.stream` object follows the same `Stream` schema documented in [Get Streams](/sdk/streams/get-streams), so you can reuse the same client-side types for both endpoints.
## Response Fields
```typescript theme={null}
wallet: WalletData
```
Wallet-specific stream data, including the wallet identity, the complete snapshot history found for that wallet in the stream, and the parent `Stream` object.
### `WalletData`
Identifier of the stream the wallet data belongs to. This duplicates the `id` path parameter in the response so downstream systems can store the wallet payload without separately carrying request context.
Wallet address whose history is being returned.
Full list of snapshots found for this wallet in the stream. Each item represents one recorded point-in-time state used for reward accumulation and wallet-level TVL accounting. APR-related fields inside each `WalletSnapshot` are only populated for token-based streams. For the canonical `WalletSnapshot` field definitions, see the `WalletSnapshot` section on the [Get Stream Wallets](/sdk/streams/get-wallets) page.
Parent stream object associated with the wallet snapshots. This uses the same schema documented in [Get Streams](/sdk/streams/get-streams).
### `Stream`
The nested `stream` field uses the same `Stream` schema returned by [Get Streams](/sdk/streams/get-streams), including fields such as `id`, `chainId`, `contractAddress`, `customArgs`, `lastSnapshot`, `committedSnapshot`, `point`, and `rewardToken`.
This means:
* you can reuse the same TypeScript or backend DTO definitions for stream parsing,
* you do not need a second request to resolve the stream metadata for the wallet detail view,
* and you can display stream configuration and wallet history together in one screen.
## Integration Notes
Because the full `snapshots` array is included, this endpoint is the correct source for historical charts, cumulative reward plots, wallet audits, and customer support views.
Reward fields are returned as strings because they may exceed the safe integer range of JavaScript numbers. Use a big-number library if you need arithmetic or unit conversion.
If you only need one row per wallet for a summary table, use [Get Stream Wallets](/sdk/streams/get-wallets) instead. It is more compact because it returns only the latest snapshot per wallet.
## Error Handling
**Status Code:** 404 Not Found
This status is returned either when the stream ID does not correspond to any known stream or when the specified wallet address has no snapshot history in that stream.
**Status Code:** 500 Internal Server Error
**Solution:** Retry the request and contact Turtle if the issue persists.
# Get Stream Wallets
Source: https://docs.turtle.xyz/sdk/streams/get-wallets
List the wallets participating in a stream, including each wallet's latest snapshot and pagination metadata
## Overview
`GET /v2/streams/{id}/wallets` returns the wallets that currently have snapshot data for a specific stream. This is a public endpoint — no API key is required.
Each returned wallet includes only its latest available snapshot for that stream. This makes the endpoint suitable for leaderboard views, partner dashboards, stream monitoring UIs, CSV exports, and paginated reporting workflows where you need a compact wallet-level summary instead of the full historical timeline.
Results are ordered by `lastSnapshot.rewardsAccumulated` in descending order, so the first wallets in the response are the ones with the highest accumulated rewards.
## Endpoint
```bash curl theme={null}
curl -X GET "https://earn.turtle.xyz/v2/streams/550e8400-e29b-41d4-a716-446655440000/wallets?page=1&limit=20"
```
```typescript TypeScript theme={null}
const streamId = '550e8400-e29b-41d4-a716-446655440000';
const page = 1;
const limit = 20;
const response = await fetch(
`https://earn.turtle.xyz/v2/streams/${streamId}/wallets?page=${page}&limit=${limit}`
);
const data = await response.json();
```
## Parameters
**Path Parameters**
Stream identifier. This is the unique UUID of the stream whose participant wallets you want to inspect.
**Query Parameters**
Page number for the paginated result set. Use this to move through the wallet list in stable chunks. Values lower than `1` are normalized by the backend to `1`.
Number of wallets to return per page. This is useful when building dashboards, tables, or exports. Values lower than `1` are normalized to `20`, and values above `100` are capped to `100` by the backend.
## Response Example
```json theme={null}
{
"data": [
{
"userAddress": "0x1111111111111111111111111111111111111111",
"lastSnapshot": {
"timestamp": "2026-03-21T00:00:00Z",
"rewardsAccumulated": "8345000000000000000",
"rewardsAccumulatedBase": "8345000000000000000",
"createdAt": "2026-03-21T00:05:00Z",
"updatedAt": "2026-03-21T00:05:00Z",
"tvl": "152340.12",
"baseTvl": "152340.12",
"baseApr": "0.105",
"apr": "0.12",
"customMetrics": {
"source": "vault-balance",
"weight": "1.00"
}
}
},
{
"userAddress": "0x2222222222222222222222222222222222222222",
"lastSnapshot": {
"timestamp": "2026-03-21T00:00:00Z",
"rewardsAccumulated": "4123000000000000000",
"rewardsAccumulatedBase": "4123000000000000000",
"createdAt": "2026-03-21T00:05:00Z",
"updatedAt": "2026-03-21T00:05:00Z",
"tvl": "97340.55",
"baseTvl": "97340.55",
"baseApr": "0.105",
"apr": "0.12",
"customMetrics": {}
}
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 42,
"totalPages": 3,
"hasNext": true,
"hasPrevious": false
}
}
```
## Response Semantics
This endpoint does not return full wallet history. Instead, each wallet entry contains a `lastSnapshot` object representing the most recent snapshot currently available for that wallet in the stream.
If the stream exists but there are no wallet snapshots yet, or if you request a page beyond the available data, the endpoint returns `data: []` together with pagination metadata instead of failing.
## Response Fields
```typescript theme={null}
data: WalletWithLastSnapshot[]
pagination: PaginationResponse
```
Paginated list of wallets that have snapshot data for the requested stream.
Pagination metadata describing the current page and the total size of the result set.
### `WalletWithLastSnapshot`
Wallet address that participated in the stream. This is the address whose balances or positions were tracked during snapshot computation. It is returned as an EVM address string.
Most recent snapshot recorded for that wallet in this stream. This object summarizes the wallet's latest reward accumulation and TVL metrics.
### `WalletSnapshot`
APR-related wallet snapshot fields are only populated for token-based streams. For point-based streams, `baseApr` and `apr` are omitted from the snapshot.
Effective timestamp of the snapshot. This is the time bucket the metrics correspond to, not necessarily the exact database write time.
Total rewards accumulated by the wallet at this snapshot, expressed in base units. For token streams, that means token wei-like units according to the reward asset decimals. For point streams, this is the accumulated point amount in the point's base precision. This field represents the reward amount after adapters have been applied (post-adapter).
Base accumulation value used by Turtle's internal reward accounting. This value reflects the accumulated rewards before adapters are applied (pre-adapter).
Timestamp when this wallet snapshot row was first created in Turtle's backend.
Timestamp of the latest update applied to this wallet snapshot row.
Time-weighted-average (TWA) USD Total Value Locked (TVL) for the wallet after adapters have been applied.
TWA USD TVL for the wallet before adapters are applied.
Base APR computed for the wallet snapshot before adapter adjustments, expressed as a decimal fraction — multiply by 100 for the percentage (for example, `0.05` means 5%). This is only populated for token-based streams.
Effective APR computed for the wallet snapshot after adapter adjustments, expressed as a decimal fraction — multiply by 100 for the percentage (for example, `0.05` means 5%). This is only populated for token-based streams.
Strategy-specific metrics captured for the wallet snapshot. Treat this field as extensible JSON. Currently, it contains the wallet's TWA token balance for the snapshot.
### `PaginationResponse`
Current page returned by the backend after normalization.
Number of items returned per page after normalization or capping.
Total number of records available for the stream across all pages.
Total number of available pages for the current `limit`.
Whether a page after the current one exists.
Whether a page before the current one exists.
## Integration Notes
Because this endpoint returns one row per wallet with only the latest snapshot, it is the best choice for ranking views, summary widgets, CSV exports, and admin pages where full historical data would be too heavy.
Reward amounts are serialized as strings to avoid precision loss in JavaScript and other environments that cannot safely represent very large integers. Keep them as strings in transit and convert them with a big-number library only when you need arithmetic.
If you need the full timeline of snapshots for one wallet, call [Get Wallet Data](/sdk/streams/get-wallet) instead of this paginated summary endpoint.
## Error Handling
**Status Code:** 404 Not Found
This happens when the `id` path parameter does not correspond to any known stream.
**Status Code:** 500 Internal Server Error
**Solution:** Retry the request and contact Turtle if the issue persists.
# Overview
Source: https://docs.turtle.xyz/sdk/streams/overview
Run points and token incentive campaigns against vault positions.
The Streams API lets you create and manage incentive distributions tied to vault positions. Use it to run points campaigns, distribute tokens to depositors, and track wallet-level reward accumulation.
Create a new token or points incentive stream.
List and filter streams for your organization.
List participating wallets and their snapshots.
View a single wallet's accumulated rewards in a stream.
Fetch Merkle proofs needed to claim token stream rewards on-chain.
Integrate on-chain reward claiming into your application.
## What is a stream
A stream is an on-chain incentive distribution tied to a set of vault positions. You define the reward token or point type, the start and end time, and the total amount to distribute. The Streams API handles the rest including merkle tree computation, snapshot scheduling, and on-chain commitment.
## Points vs token streams
The API supports two stream types:
* **Points streams** use off-chain point systems. Points are tracked by Turtle and can be queried per wallet. They are useful for gamification, loyalty programs, and pre-token incentive campaigns.
* **Token streams** distribute ERC-20 tokens on-chain via a smart contract. Token allocations are computed per snapshot and committed to a merkle tree that users can claim against.
# Get Streams (Bulk)
Source: https://docs.turtle.xyz/sdk/streams/post-streams-bulk
Retrieve confirmed streams using multi-valued filters in the request body, with optional pagination
## Overview
`POST /v2/streams/bulk` returns confirmed streams using the same `Stream` objects as [Get Streams](/sdk/streams/get-streams). This is a public endpoint. No API key is required.
It uses `POST` only so that multi-valued filters can be sent in the request body. Despite the verb, it is a **read-only query**: nothing is created or modified, and the result set is **not** scoped to any API key's organization.
This endpoint is the bulk counterpart of [Get Streams](/sdk/streams/get-streams). Reach for it when [Get Streams](/sdk/streams/get-streams) is too limited, specifically when you need to:
1. **Filter by multiple values at once**: several stream IDs, several organizations, one or more target-token chains, or a set of `(chainId, address)` target tokens, instead of the single-value query params accepted by [Get Streams](/sdk/streams/get-streams).
2. **Paginate** the result set with the optional `page` and `limit` query params.
Filters of different kinds are combined with `AND`; multiple values within a single filter are combined with `OR`. As with [Get Streams](/sdk/streams/get-streams), only confirmed streams are ever returned.
`targetChainIds` and `targetTokens` filter on each stream's **target token** (the token tracked via `customArgs.targetTokenId`), not its reward token. Use the decimal EVM chain IDs listed in [Get Tokens](/sdk/streams/get-tokens).
## Endpoint
### Filter by multiple stream IDs
```bash curl theme={null}
curl -X POST "https://earn.turtle.xyz/v2/streams/bulk" \
-H "Content-Type: application/json" \
-d '{
"ids": [
"550e8400-e29b-41d4-a716-446655440000",
"6f0f2a1c-1c2d-4f3e-9a8b-7c6d5e4f3a2b"
]
}'
```
```typescript TypeScript theme={null}
const response = await fetch('https://earn.turtle.xyz/v2/streams/bulk', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
ids: [
'550e8400-e29b-41d4-a716-446655440000',
'6f0f2a1c-1c2d-4f3e-9a8b-7c6d5e4f3a2b',
],
}),
});
const data = await response.json();
```
### Filter by chain and token (no org ID)
This is the no-auth-context path for a frontend that only needs to read reward streams for specific tokens on specific chains. It passes no distributor or organization ID and needs no API key. Send `targetChainIds`, `targetTokens`, or both.
```bash curl theme={null}
curl -X POST "https://earn.turtle.xyz/v2/streams/bulk?limit=50" \
-H "Content-Type: application/json" \
-d '{
"targetChainIds": [1, 8453],
"targetTokens": [
{ "chainId": 1, "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" }
]
}'
```
```typescript TypeScript theme={null}
const response = await fetch(
'https://earn.turtle.xyz/v2/streams/bulk?limit=50',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
targetChainIds: [1, 8453],
targetTokens: [
{ chainId: 1, address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' },
],
}),
}
);
const data = await response.json();
```
### Filter by organizations and target tokens
```bash curl theme={null}
curl -X POST "https://earn.turtle.xyz/v2/streams/bulk" \
-H "Content-Type: application/json" \
-d '{
"organizationIds": ["9f51b66a-d13a-4b55-8515-ae6e4ef7cf25"],
"targetChainIds": [1, 8453],
"targetTokens": [
{ "chainId": 1, "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" }
],
"withSnapshots": false,
"usersCount": true
}'
```
```typescript TypeScript theme={null}
const response = await fetch('https://earn.turtle.xyz/v2/streams/bulk', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
organizationIds: ['9f51b66a-d13a-4b55-8515-ae6e4ef7cf25'],
targetChainIds: [1, 8453],
targetTokens: [
{ chainId: 1, address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' },
],
withSnapshots: false,
usersCount: true,
}),
});
const data = await response.json();
```
### Paginate the result set
Pagination is opt-in. Send `page` and/or `limit` as **query parameters** to receive one page plus a `pagination` object in the response.
```bash curl theme={null}
curl -X POST "https://earn.turtle.xyz/v2/streams/bulk?page=1&limit=50" \
-H "Content-Type: application/json" \
-d '{ "organizationIds": ["9f51b66a-d13a-4b55-8515-ae6e4ef7cf25"] }'
```
```typescript TypeScript theme={null}
const response = await fetch(
'https://earn.turtle.xyz/v2/streams/bulk?page=1&limit=50',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
organizationIds: ['9f51b66a-d13a-4b55-8515-ae6e4ef7cf25'],
}),
}
);
const data = await response.json();
```
## Parameters
### Request Body
All body fields are optional. Sending an empty body is allowed, but only together with a bounded `limit` query parameter (see [Response Semantics](#response-semantics)).
Filter by stream IDs. Returns streams whose `id` is in this list.
Filter by owning organization IDs. Returns streams belonging to any of these organizations.
Filter by streams whose target token is on any of these chains. Values are decimal EVM chain IDs. See [Get Tokens](/sdk/streams/get-tokens) for the supported list.
Filter by streams whose target token matches any of these EVM `(chainId, address)` tokens.
Include the full historical `snapshots` array for each returned stream. Behaves exactly as on [Get Streams](/sdk/streams/get-streams).
Add `userCount` and `activeUserCount` to each included snapshot object. Behaves exactly as on [Get Streams](/sdk/streams/get-streams).
#### `EvmToken`
Decimal EVM chain ID of the target token.
Target token contract address on that chain. Matching is case-insensitive.
### Query Parameters
Pagination is optional. Omit both parameters to return **all** matching streams in a single response, without a `pagination` object.
Page number for the paginated result set. Providing `page` or `limit` switches the endpoint into paginated mode. Values lower than `1` are normalized by the backend to `1`.
Number of streams to return per page. Providing `page` or `limit` switches the endpoint into paginated mode. Values lower than `1` are normalized to `20`. Values above `500` are rejected with `400 Invalid Argument`.
## Response Example
When pagination is requested, the response includes a `pagination` object. The `streams` array holds the same `Stream` objects documented in [Get Streams](/sdk/streams/get-streams).
```json theme={null}
{
"streams": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"chainId": 1,
"contractAddress": "0x4C6F5a1aA2B9985d4A8b9189C2118E7f55E2f701",
"orgId": "9f51b66a-d13a-4b55-8515-ae6e4ef7cf25",
"type": 2,
"strategy": "Fixed APR",
"startTimestamp": "2026-03-11T00:00:00Z",
"endTimestamp": "2026-04-11T00:00:00Z",
"lastSnapshot": { "...": "see Get Streams for the full Stream object" },
"snapshots": [],
"rewardToken": { "...": "see Get Streams" },
"estimatedLiveApr": "0.12"
}
],
"pagination": {
"page": 1,
"limit": 50,
"total": 128,
"totalPages": 3,
"hasNext": true,
"hasPrevious": false
}
}
```
The `Stream` object is identical to the one returned by [Get Streams](/sdk/streams/get-streams). See that page for the complete field-by-field schema, including `customArgs`, `adapters`, `point`, `lastSnapshot`, `committedSnapshot`, `snapshots`, `rewardToken`, and `estimatedLiveApr`. As on Get Streams, use `estimatedLiveApr` — not `lastSnapshot.apr` — for the rate a stream is currently distributing; see [Live APR vs snapshot APR](/sdk/streams/get-streams#live-apr-vs-snapshot-apr).
## Response Semantics
Sending `organizationIds` and `targetChainIds` together returns streams that belong to one of the organizations **and** whose target token is on one of the chains. Within a single filter, multiple values are matched with `OR` (an `IN` lookup).
If you omit both `page` and `limit`, the endpoint returns every matching stream and no `pagination` object. As soon as either query parameter is present, the response is paginated and includes a `pagination` object.
To avoid loading the entire stream table, an empty body (no `ids`, `organizationIds`, `targetChainIds`, or `targetTokens`) must be paired with a bounded `limit` query parameter. Without a filter and without a `limit`, the request is rejected with `400 Invalid Argument`.
Like [Get Streams](/sdk/streams/get-streams), this endpoint only returns streams whose creation has been confirmed. Pending streams are never included.
If no stream matches the provided filters, the endpoint returns `streams: []` (together with a `pagination` object when pagination was requested) rather than failing.
## Response Fields
```typescript theme={null}
streams: Stream[]
pagination?: PaginationResponse
```
List of confirmed streams matching the provided filters. Each item is a `Stream` object, including `estimatedLiveApr`. See [Get Streams](/sdk/streams/get-streams) for the full schema.
Pagination metadata describing the current page and the total size of the result set. Present only when `page` or `limit` was supplied; omitted otherwise.
### `PaginationResponse`
Current page returned by the backend after normalization.
Number of items returned per page after normalization or capping.
Total number of streams matching the filters across all pages.
Total number of available pages for the current `limit`.
Whether a page after the current one exists.
Whether a page before the current one exists.
## Error Handling
**Status Code:** 400 Bad Request
```json theme={null}
{
"error": {
"status": "INVALID_ARGUMENT",
"error": "a bounded limit (max 500) is required when no filter is provided"
}
}
```
**Solution:** Provide at least one filter (`ids`, `organizationIds`, `targetChainIds`, or `targetTokens`), or supply a bounded `limit` query parameter.
**Status Code:** 400 Bad Request
Each filter has an upper bound: 100 `ids`, 20 `organizationIds`, 5 `targetChainIds`, and 100 `targetTokens`. Exceeding any of these returns `INVALID_ARGUMENT` with a message such as `too many stream ids (max 100)`.
**Solution:** Split large requests into multiple calls that stay within the per-filter limits.
**Status Code:** 400 Bad Request
```json theme={null}
{
"error": {
"status": "INVALID_ARGUMENT",
"error": "limit too high (max 500)"
}
}
```
**Solution:** Request a `limit` of 500 or fewer and page through the result set.
**Status Code:** 500 Internal Server Error
**Solution:** Retry the request and contact Turtle if the issue persists.
# Genesis Airdrop Eligibility
Source: https://docs.turtle.xyz/token/airdrop
How Genesis Airdrop eligibility was determined, plus claim and vesting mechanics.
See full announcement [here](https://x.com/turtledotxyz/status/1976264305092739543).
This is the page for all \$TURTLE airdrop and eligibility questions.
## How to check eligibility and claim
Claiming happens in the [Turtle app](https://app.turtle.xyz) with the wallet you used to contribute to the Turtle DAO. Allocations are tied to that wallet, so connecting a different one shows nothing to claim.
1. Open the [Turtle app](https://app.turtle.xyz) and connect your wallet.
2. Go to the [Liquidity Campaigns page](https://app.turtle.xyz/deals) and check the **Your Earnings** section to see your eligible allocation.
3. If you have an allocation, follow the in-app prompt to claim. Read [Vesting & Mechanics](#vesting--mechanics) before claiming — claiming once forfeits any unvested portion.
If **Your Earnings** shows no allocation, review the [eligibility criteria](#general-criteria) below. Wallets connected after the pre-TGE snapshot, or with no measurable DAO contribution, are not eligible.
## Eligibility
Eligibility for the Genesis Airdrop was determined based on real, value-added participation across Turtle’s ecosystem. Every wallet was reviewed to ensure alignment with the DAO’s purpose and contribution model.
#### General Criteria
* See *Past Liquidity Campaigns* section at the bottom of [this page](https://app.turtle.xyz/deals) to view the liquidity campaigns that contributed to the DAO treasury.
* Only wallets that have contributed value to the Turtle DAO qualify.
* Sybil and bot activity were systematically removed.
* Eligibility was verified through on-chain data, partner payments, and verified user contributions.
#### For NFT Holders & OG Discord Members
* Holders of the Turtle OG or BeraChain NFT badges must have contributed at least \$1 to the DAO.
* Simply holding the NFT or Discord role does not qualify if no verifiable contribution was made.
* Wallets that never connected to the Turtle dApp or participated in liquidity campaigns are not eligible.
* Wallets that were connected after the snapshot (weeks prior to the TGE) are not eligible.
#### For Yield Boost / Liquidity Campaign Participants
* Eligibility is based on actual contributions and partner protocol payments received by the Turtle DAO.
* Users can verify their participation by visiting the Liquidity Campaigns Page and checking the “Your Earnings” section.
#### For Campaigns
* The Turtle TAC Campaign was *the only campaign* with Turtle Token emissions assigned via a deposit bonus.
#### For Leaderboard
* The only Liquidity Campaigns eligible for leaderboard distribution must have been deposited via the Turtle UI.
* The only Campaign Vaults eligible for leaderboard distribution were TAC, Katana, and Avalanche (not Linea).
* The leaderboard recorded rankings every week. At snapshot before TGE, Turtles who ranked in the top 1000 received a pro-rata allocation of 0.2% of the \$TURTLE supply.
#### For Partner & Referral Participants
* Verified partners, distributors, and referrers who expanded Turtle’s liquidity network or brought new users prior to the Liquidity Leaderboard launch are included.
* Only referrals that led to real activity or deposits were counted.
#### Exclusions
* Wallets that submitted forms but had no measurable DAO contribution are excluded.
* Duplicate submissions, bot-generated wallets, or addresses with no connected activity were filtered out.
## Vesting & Mechanics
Airdropped tokens are structured to balance immediate access with gradual release.
If your total claimable amount is **1,700**
[**\$TURTLE**](https://x.com/search?q=%24TURTLE\&src=cashtag_click)
**or less** , your tokens will be **fully unlocked at TGE**, with no vesting.
For allocations **above 1,700**
[**\$TURTLE**](https://x.com/search?q=%24TURTLE\&src=cashtag_click)
* **70%** is claimable immediately at TGE.
* The remaining **30%** vests **linearly over 12 weeks**, starting from the TGE date.
You can claim only once. Once you claim, you’ll forfeit any unvested tokens! These will be returned to the treasury or burned.
**Examples:**
* **User 1:** Claims at TGE day 1 → receives **70%**, forfeits **30%**.
* **User 2:** Claims after 12 weeks → receives **100%**.
* **User 3:** Claims after 4 weeks → receives **≈80%** (70% initial + 10% vested), forfeits 20%.
# Contracts
Source: https://docs.turtle.xyz/token/contracts
TURTLE token and protocol contract addresses by chain.
Updated 10/21/25
| Type | Chain | Address |
| ------------------------ | ----- | ---------------------------------------------- |
| **TURTLE** | ETH | **0x66fd8de541c0594b4dccdfc13bf3a390e50d3afd** |
| **TURTLE** | BSC | **0x66fd8de541c0594b4dccdfc13bf3a390e50d3afd** |
| **TURTLE** | Linea | **0x56aa6d651bfefa9207b35e508716466359bae8ef** |
| **sTURTLE** | ETH | **0x2d362158034EEB28e1a7062F24FfC436b1D01858** |
| **sTURTLE (deprecated)** | ETH | **0x233CBC0109475B5a85da23b997105FC16b73E7Fc** |
| **Drip Contract** | BSC | **0x56aa6D651bfefA9207B35E508716466359BAe8eF** |
| **Staking Contract** | ETH | **0x7c329f3269d47ab58ef225f9f4a1f488dfd48825** |
| **CCIP Bridge Pool** | ETH | **0xd3bd7db2b40dbee54ca70a34921fde8a8d2f8bbb** |
| **CCIP Bridge Pool** | BSC | **0x4559605e3003fda8c059e14af4f16ba9a004335a** |
| **CCIP Bridge Pool** | Linea | **0x7263bc9f9d2f94e9a3bcb3efb40c79c43ac0c647** |
| **DAO Multisig** | ETH | **0x2e0355922EF3a5b77d29287C808aEafB4e7f25B2** |
| **Governor** | ETH | **0x27cbB991EfF5E5c7b6734675E837EDDF924Ffece** |
## Audits
These contracts have been reviewed by independent security firms. See [Audit Reports](/resources/audits) for the full list.
# Turtle Governance
Source: https://docs.turtle.xyz/token/governance
$TURTLE utility, the staking-to-sTURTLE voting flow, and Governor parameters.
\$TURTLE is the utility token that powers the Turtle liquidity protocol, aligning users, partners, and contributors under a shared network of onchain liquidity distribution.
At launch, holders can **stake TURTLE for sTURTLE**, gaining the ability to delegate and vote on governance proposals that shape the protocol’s future.
**Core Utility**
* **Governance:** stake TURTLE → receive sTURTLE → delegate or vote directly on proposals.
* **Contribution Incentives:** receive token grants or rewards for verifiable liquidity contributions and integrations.
* **Alignment Mechanism:** demand for influence and participation drives TURTLE’s core utility across the network.
**Value Drivers**
* **Governance Demand:** holders seeking to influence treasury management, protocol direction, and integrations.
* **Ecosystem Growth:** incentives for contributors, LPs, and partners participating in campaigns and integrations.
* **Network Effects:** as the protocol routes more liquidity, demand for influence and participation naturally increases.
**Future Utility**
At launch, \$TURTLE functions primarily as a governance and alignment token. Over time, its utility will expand based on **community and governance decisions** to reflect the evolving needs of the Turtle ecosystem.
Future utilities **may** include:
* Expanded access to liquidity options
* Fee discounts and yield boosts across core products
* Protocol buybacks or redistributive mechanisms
* Enhanced staking tiers and governance modules
Ultimately, **governance will define the future of \$TURTLE**, shaping how it evolves to sustain alignment, value, and long-term participation across the network.
## Governance System
### Purpose
Turtle governance will use Tally’s tooling to simplify the governance process. To begin, the system will use the out-of-the-box governance framework provided by the Governor contract. Find all details below.
The governance system for Turtle focuses on keeping the network aligned with the best interests of its stakeholders.
### Stakeholders
Turtle governance entities include a variety of stakeholders with different functions, powers, and responsibilities.\
*User Types:*
* **TURTLE Holders**: holders of the TURTLE token. These users have the opportunity to stake for sTURTLE and delegate their stake to themselves or a qualified delegate.
* **sTURTLE Holders**: holders who have staked their TURTLE. These users still need to delegate to themself or a Turtle delegate to activate their voting power.
* **Turtle Delegates**: any user on the Internet can sign up to [Tally](https://www.tally.xyz/explore) and campaign as a Turtle Delegate. These users can delegate sTURTLE to themself, or campaign to gather delegated voting power from others.
* **Turtle DAO**: the Turtle DAO includes the larger network of all token holders, partners, users, and builders.
* **Turtle Core Team**: Due to the nature of the protocol, Turtle’s Core Team will be responsible for implementing governance decisions as they progress through the process.
* **Canceller**: the address associated with the power to cancel a proposal in the governance system.
### Process
1. Creation: Turtle delegates with the defined limit (proposalThreshold) of sTURTLE voting power have the opportunity to create governance proposals.
2. Voting: once a proposal voting process begins, a snapshot of all sTURTLE holders and amount of sTURTLE in circulation defines the weights of all voting participants and the quorum amount needed to pass.
3. Execution: due to the nature of the protocol, Turtle's governance leverages onchain voting and offchain execution by Core Team or Foundation to enact.
### Voting Parameters
The governance contract utilizes Open Zeppelin’s Governor contract. Token holders will be able to stake any amount of TURTLE to receive sTURTLE and then must delegate to utilize their voting power (note: sTURTLE holders can self-delegate if they want to vote on their own).
Once a delegate is chosen, the address commits their total sTURTLE voting power to that delegate. If the user delegating their vote increases or decreases their staked amount, the sTURTLE voting power given to their delegate will change accordingly.
*Parameters*:
* *Proposal threshold (1.5M)*
This is the minimum amount of voting power a user must be delegated in order to create a proposal. If someone does not have sufficient power delegated to them, they cannot submit a proposal to be voted on.
**Quorum (4% of sTURTLE)**
This defines the minimum number of votes that must be cast for a proposal to be considered valid. If the quorum is not reached, the proposal fails regardless of the voting outcome.
**Voting delay (4 days)**
This defines the waiting period between when a proposal is created and when voting can officially begin. It ensures that all community members have time to review the proposal before voting starts.
**Voting period (2 weeks)**
This defines the duration during which Turtle delegates can cast their votes on a proposal. Once this time expires, the voting ends and the outcome is finalized.
**Timelock Delay (NA)**
The timelock delay is the minimum amount of time between when a proposal passes and when it can be executed. **This parameter is only relevant for proposals that require onchain execution.**
# Stake $TURTLE
Source: https://docs.turtle.xyz/token/stake-turtle
Stake $TURTLE to boost the Turtle Shells you earn in the Liquidity Leaderboard.
Stake \$TURTLE to earn a boost on the [Turtle Shells](/resources/glossary) you accrue in the [Liquidity Leaderboard](/liquidity-products/leaderboard).
How the boost works:
1. Deposit into a Turtle liquidity campaign on the [Liquidity Campaigns page](https://app.turtle.xyz/deals).
2. Stake the full USD value of the deposit to earn the maximum boost.
*The boost is applied linearly based on the ratio of your sTURTLE value to your cumulative TVL across Turtle deals. For example, if you hold \$10K of sTURTLE and a cumulative \$10K of TVL across Turtle deals, you earn the maximum boost.*
More tokenized utility coming soon!
# Tokenomics
Source: https://docs.turtle.xyz/token/tokenomics
TURTLE supply allocation and vesting schedule.
## Turtle Vesting Schedule
## Allocations
| **Category** | **% of Supply** | **Cliff** | **Vesting** |
| :-------------------------------- | :-------------- | :-------- | :------------------------------- |
| Private Rounds (Investors) | 27.50% | 6 months | 36-month linear |
| Airdrop | 12.10% | None | Claim/linear (per airdrop rules) |
| Team, Advisors, Contributors | 23.10% | 12 months | 36-month linear |
| Liquidity, MM & Exchange Reserves | 8.00% | None | TGE unlock |
| Ecosystem / Community | 29.30% | None | Governance-directed unlocks |
| **Total** | **100%** | - | - |
\*Subject to change at the close of the latest investment round.
# Transparency
Source: https://docs.turtle.xyz/transparency
Turtle Transparency Documentation
Turtle is committed to full transparency with our community, token holders, and ecosystem partners. We publish the following core documents and make them freely accessible to anyone.
## Token Transparency Filing
**Blockworks B-2 Token Transparency Filing** In April 2025, Turtle completed the Blockworks Token Transparency Framework, a standardized industry disclosure regime covering project structure, revenue streams, equity-token relationships, supply allocation, vesting policies, insider transactions, market maker arrangements, and financial reporting. The filing was independently audited and received a score of **40/40**, reflecting Turtle's commitment to disclosing every material aspect of its tokenomics, governance, and operations to the public.
[→ More on the Token Transparency Framework](https://blockworks.com/token-transparency)
[→ Read the Turtle Token Transparency Report](https://drive.google.com/file/d/12HOHaIw4vgxPbB8gUsDZdUrVt-ZxA9N_/view?usp=drive_link)
## Financial Reporting
**Quarterly Financial Reports** We publish quarterly reports covering treasury activity, token movements, revenue streams, operational spend, and any material events affecting the protocol or the Turtle Club Association.
* [Q4 2025 Financial Report](https://drive.google.com/file/d/1XDtgfL2wDSJLfGlAo7FS0ArzivkwvUe6/view?usp=drive_link)
* [**Q1 2026 Financial Report**](https://drive.google.com/file/d/1i9BxGZ_cdPyU0lrDp263FJAPhL3pjr-X/view)
Future quarterly reports will be published on this page within 45 days of each quarter's close.
## Whitepapers and Regulatory Filings
**MiCA Crypto-Asset White Paper** Turtle's white paper filed in accordance with Title II of Regulation (EU) 2023/1114 (MiCA). It sets out the characteristics of the TURTLE token, the rights and obligations attached to it, the underlying technology, risk factors, and sustainability indicators, and serves as the reference document supporting admission to trading across EU Member States.
→ [Read the MiCA White Paper](https://drive.google.com/file/d/1d2rz30MmLfU0NnbbU8tWsHvN1r9DyYUX/view?usp=drive_link)
The general Turtle whitepaper is in progress and will be published here when it is ready.
## Governance & Token Policy
**Turtle Master Token Incentive Plan (TMTIP)** The governing document for all TURTLE token incentive allocations, covering eligibility, vesting, distribution mechanics, and the long-term alignment framework between the protocol, contributors, and the community. \
\
→ [Read the TMTIP](https://drive.google.com/file/d/1BzbqtaHF3cxZKAHMhnoIZpCAghm7Kso-/view?usp=drive_link)
## Additional Disclosures
For information on our legal entity (Turtle Club Association, a Swiss Verein registered under UID CHE-258.098.477 in Zug, Switzerland), token supply schedule, team allocations, and advisor arrangements, see the [Terms](/legal/terms) and [Privacy Statement](/legal/privacy-policy).
Questions, corrections, or requests for further disclosure can be sent to [transparency@turtle.xyz](mailto:transparency@turtle.xyz).