# Welcome

This is the developer documentation for Trustless Work.

Trustless Work is **Escrow-as-a-Service (EaaS)** for **stablecoin escrow**. Build **non-custodial** flows with **milestones**, approvals, and disputes. Contracts run on **Stellar (Soroban)**. Your app drives them via API or SDK.

{% embed url="<https://youtu.be/AZHv48hYxNg>" %}

### Start here

<table data-view="cards"><thead><tr><th>Topic</th><th data-card-target data-type="content-ref">Link</th></tr></thead><tbody><tr><td>Developer Quickstart</td><td><a href="/pages/AquDVsvmK0dqV0bXsAkp">/pages/AquDVsvmK0dqV0bXsAkp</a></td></tr><tr><td>Request an API key</td><td><a href="/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/rk6FfPZG0cVD1uYYThg4">/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/rk6FfPZG0cVD1uYYThg4</a></td></tr><tr><td>REST API basics (base URLs, limits, Swagger)</td><td><a href="/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/zjyQfhCFZuBXwRacP8gA">/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/zjyQfhCFZuBXwRacP8gA</a></td></tr><tr><td>React SDK (hooks)</td><td><a href="/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/rxYPNF9iKlXPgPA9et2e">/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/rxYPNF9iKlXPgPA9et2e</a></td></tr><tr><td>Escrow Blocks SDK (UI blocks)</td><td><a href="/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/wFkVynLE898UKQcf0EuW">/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/wFkVynLE898UKQcf0EuW</a></td></tr><tr><td>Escrow concepts (roles, lifecycle, types)</td><td><a href="/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/x6BXXXSuTkWdsdG6xFvF">/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/x6BXXXSuTkWdsdG6xFvF</a></td></tr><tr><td>Stellar rails (trustlines, wallets)</td><td><a href="/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/dwu3u6HTiZUFnVq02ssU">/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/dwu3u6HTiZUFnVq02ssU</a></td></tr><tr><td>Use cases by industry</td><td><a href="/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/Zrn4BJ7EVzfZPBFh9ofd">/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/Zrn4BJ7EVzfZPBFh9ofd</a></td></tr><tr><td>All links (docs, tools, external)</td><td><a href="/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/P53vwWf6uYYh4OTEQAyu">/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/P53vwWf6uYYh4OTEQAyu</a></td></tr></tbody></table>

### What you can build

* Hold funds in escrow using **non-custodial smart contracts**.
* Add **programmable release logic** to your app or marketplace.
* Support **milestones**, approvals, partial releases, and disputes.
* Configure **roles and permissions** per signer.
* Launch faster without writing escrow contracts from scratch.

### Common escrow use cases

* Marketplace escrow for e-commerce and services.
* Freelance and contract escrow with milestone payouts.
* Security deposits for rentals and reservations.
* Crowdfunding and pre-orders with conditional payouts.
* Grants and programmatic disbursements.

### Try it in minutes

<a href="https://dapp.trustlesswork.com/" class="button primary">Open Backoffice dApp</a>

<a href="https://demo.trustlesswork.com/" class="button secondary">Open demo dApp</a>

<a href="https://api.trustlesswork.com/docs" class="button secondary">Open Swagger (Mainnet)</a>

<a href="https://github.com/Trustless-Work" class="button secondary">View GitHub</a>


# AI optimized docs

Trustless Work docs are written for humans **and** for machines.

Humans get clarity, precision, and examples. Agents get structure, consistency, and predictable semantics.

### Why this matters

The next generation of builders won’t just code. They’ll prompt, automate, and delegate work to agents.

An AI-ready doc set lets you:

* Export content for training and internal copilots.
* Feed pages into your LLM memory or RAG pipeline.
* Let agents reason through flows and generate SDK/API calls.

{% hint style="info" %}
Goal: make the documentation itself a building block for automation.
{% endhint %}

### Export formats

You can export any section of the docs as PDF or Markdown.

<figure><img src="/files/5eTcrhZWCBddAV6o3SJB" alt=""><figcaption></figcaption></figure>

* **PDF** for onboarding manuals and reference packs.
* **Markdown (.md)** for ingestion and context injection.
* **Prompt blocks** for pasting into GPT, Cursor, or v0.dev.

{% hint style="success" %}
Check the SDK pages for prompt-first workflows that generate and debug escrow flows.
{% endhint %}

### Ask the docs (search)

Search is optimized for natural language. Use intent-focused prompts, not just keywords.

Example prompts:

```
fund a multi-release escrow with testnet USDC
create an SDK snippet to mark milestone as done
explain the difference between approver and release signer
```

{% hint style="info" %}
Search rewrites your question into a structured query and returns the best snippets.
{% endhint %}


# Why Escrows Matter

Escrow is a neutral way to hold funds until conditions are met. It’s the simplest primitive for “trust, but verify”.

### Escrow is the trust layer

Most people first think of real estate. That’s correct. Escrow is common in high-value transactions.

<figure><img src="/files/a64fNjAXeqEqoHyfXMnk" alt=""><figcaption><p>Simple representation of a Real Estate Escrow.</p></figcaption></figure>

Escrow also shows up in marketplaces (Upwork, eBay, etc.).

<figure><img src="/files/2imk1tvnPSDNYDMB49uK" alt=""><figcaption><p>Escrows on digital marketplaces.</p></figcaption></figure>

Big platforms can afford escrow infrastructure. Many others can’t.

eBay leans on legacy providers (often 3%–8% fees). Upwork invested heavily in escrow operations.

Platforms that could greatly benefit from the use of escrows don't use them because of the technical complexity and cost of building an escrow infrastructure.

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

### Why legacy escrow is hard

* **Fiat escrow is expensive and slow.** It typically requires bank rails and settlement workflows.
* **It’s operationally heavy.** Real estate, M\&A, and cross-border trade use escrow because they can justify the overhead.

{% hint style="warning" %}
Some teams spend months to a year building escrow infrastructure.
{% endhint %}

### Why smart-contract escrow wins (but still hurts to build)

Blockchain makes escrow programmable and auditable. But building production-grade contracts and flows still takes specialized time. Most teams don’t want to hire a full smart contract team for v1.

### What escrow solves

* **Chargebacks** and fraud in marketplaces
* **Late or withheld payments** for freelancers
* **Unclear fund control** in grants, bounties, or pre-orders
* **No dispute path** in P2P or milestone deals

### What Trustless Escrow enables

* Payments release only when work is approved.
* Funds sit in secure, neutral smart contracts.
* Approval flows can be signed by users, platforms, or agents.
* Works globally with USDC and Stellar settlement.

### Next steps

* Get started: [Developer Quickstart](broken://spaces/Dg2e2YCRmNlhCnxxmEb6/pages/bknsGrFeT0G5xw1ebl4u)


# Who Should Use This

Trustless Work is built for developers, platforms, and agents who want **more control and automation** over when funds are released.

### Platforms using stablecoins

Examples:

* Gig and freelance platforms (milestone payouts)
* B2B tools using USDC for global settlement
* Rental and booking platforms (security deposits)

Why it fits:

* Reduce fraud
* Automate releases and disbursements
* Lower operational cost

### Builders and product teams

Examples:

* Solo devs or small teams prototyping dApps
* DAO tooling, donation platforms, on-chain marketplaces

Why it fits:

* Plug-and-play escrow logic
* Start on testnet, then go live without re-architecting

### Enterprise use

Examples:

* Platforms with escrow-like flows but no escrow infrastructure
* Teams replacing costly custodial services with on-chain escrow

Why it fits:

* Less legal and operational risk than custody
* Programmable, auditable escrow behavior

### Next steps

* Build your first flow: [Developer Quickstart](broken://spaces/Dg2e2YCRmNlhCnxxmEb6/pages/bknsGrFeT0G5xw1ebl4u)


# Links

Quick links to core docs, tools, and external resources.

### 🧭 Core Docs

<table data-view="cards"><thead><tr><th>Title</th><th data-card-target data-type="content-ref">Link</th></tr></thead><tbody><tr><td>Developer Quickstart</td><td><a href="/pages/AquDVsvmK0dqV0bXsAkp">/pages/AquDVsvmK0dqV0bXsAkp</a></td></tr><tr><td>API Reference</td><td><a href="/pages/zjyQfhCFZuBXwRacP8gA">/pages/zjyQfhCFZuBXwRacP8gA</a></td></tr><tr><td>React SDK</td><td><a href="/pages/Axl3sJ9gmLZkGt0gHS2Q">/pages/Axl3sJ9gmLZkGt0gHS2Q</a></td></tr></tbody></table>

### 🛠️ Tools

<table data-view="cards"><thead><tr><th>Title</th><th>Link</th></tr></thead><tbody><tr><td>Backoffice</td><td><a href="https://dapp.trustlesswork.com/">dapp.trustlesswork.com</a></td></tr><tr><td>Demo</td><td><a href="https://demo.trustlesswork.com/">demo.trustlesswork.com</a></td></tr><tr><td>Escrow Viewer</td><td><a href="https://viewer.trustlesswork.com/">viewer.trustlesswork.com</a></td></tr><tr><td>Swagger API Docs</td><td><a href="https://dev.api.trustlesswork.com/docs">https://dev.api.trustlesswork.com/docs</a></td></tr></tbody></table>

### 🌐 External Links

<table data-view="cards"><thead><tr><th>Title</th><th data-type="content-ref"></th></tr></thead><tbody><tr><td>Website</td><td><a href="https://trustlesswork.com">https://trustlesswork.com</a></td></tr><tr><td>GitHub</td><td><a href="https://github.com/Trustless-Work">https://github.com/Trustless-Work</a></td></tr><tr><td>GrantFox</td><td><a href="https://contribute.grantfox.xyz/">https://contribute.grantfox.xyz/</a></td></tr></tbody></table>


# Escrow Design

We don’t hold your money—we hold the logic.

Trustless Work escrows are programmable trust primitives. They allow platforms, marketplaces, applications, and organizations to define how funds should be held, updated, approved, and released between different parties.\
\
An escrow is not only a place where funds sit.

It is a coordination layer between:

* parties
* funds
* roles
* milestones
* status updates
* approvals
* release conditions
* platform fees
* dispute or exception flows

Before creating an escrow, the most important question is:

> Who must do what before money can move?

If you can answer that clearly, you can design a good escrow.

***

### The Escrow Design Mental Model

Before choosing an escrow type or calling the API, map the transaction.

Start with four questions:

1. **Who are the parties involved?**
2. **Where are the funds moving?**
3. **Who has permission to update, approve, and release?**
4. **What conditions must be met before funds are released?**

This is the foundation of escrow design.

Trustless Work gives you the infrastructure to turn that logic into a smart escrow.

***

### Step 1: Map the Parties

Every escrow involves parties.

Some parties fund the escrow.\
Some perform work.\
Some update status.\
Some approve completion.\
Some resolve disputes.\
Some release funds.\
Some receive funds.\
Some receive platform fees.

Common roles include:

| Party                               | What they represent                                                    |
| ----------------------------------- | ---------------------------------------------------------------------- |
| Receiver                            | The party that receives funds after release                            |
| Service Provider / Milestone Marker | The party that updates progress or marks work as completed             |
| Approver                            | The party that validates whether a milestone or condition has been met |
| Release Signer                      | The party that signs or triggers the release of funds                  |
| Platform Address                    | Can make changes before escrow is funded and receives the platform fee |
| Dispute Resolver                    | Arbitrates disputes and can re-route funds when a dispute is raised    |

Roles are assigned to addresses.

Only the address assigned to a role can perform the actions allowed for that role.

The same real-world person, organization, or wallet can sometimes hold multiple roles, but role combinations should be intentional.

For example, a freelancer may be both the **Receiver** and the **Service Provider**, but they usually should not also be the **Approver** of their own work.

***

### Step 2: Map Fund Direction

Next, map how funds should move.

The fund direction should answer:

> Who funds the escrow, and who should receive funds after the right conditions are met?

### Pattern 1: Marketplace Payment

Use case: **Single-release escrow**

A buyer hires or purchases from a seller, freelancer, or service provider. The buyer funds the escrow. The service provider delivers the work or product. The approver validates completion. Then funds are released once.

```txt
Buyer / Client
    → funds escrow
        → Seller / Service Provider receives one final payout
```

### Pattern 2: Project Milestones

Use case: **Multi-release escrow, same receiver**

A client funds a project that has multiple milestones. The same service provider receives payments progressively as each milestone is completed and approved.

```
Client
    → funds escrow
        → Milestone 1 payout to same receiver
        → Milestone 2 payout to same receiver
        → Milestone 3 payout to same receiver
```

### Pattern 3: Payouts

Use case: **Multi-release escrow, multiple receivers**

A sponsor, platform, or organization funds one escrow that needs to pay different people or entities across different milestones.

```
Sponsor / Platform
    → funds escrow
        → Milestone 1 payout to Receiver A
        → Milestone 2 payout to Receiver B
        → Milestone 3 payout to Receiver C
```

***

### Step 3: Separate Status, Approval, and Release

A common mistake is treating status updates, approvals, and fund releases as the same thing.

In Trustless Work, these should be understood separately:

| Concept  | Meaning                                  |
| -------- | ---------------------------------------- |
| Status   | Communication about progress             |
| Approval | Validation that a condition has been met |
| Release  | Execution of the payment                 |

#### Status = Communication

A status update tells the other parties what is happening.

Examples:

* work started
* paperwork submitted
* shipment in transit
* delivery completed
* milestone ready for review
* evidence uploaded

The Service Provider or Milestone Marker usually updates the milestone status.

Status updates can happen many times before a milestone reaches its final expected state.

#### Approval = Validation

Approval means an authorized party has validated that the agreed condition was met.

For example:

* the client approves the work
* the grant reviewer approves the deliverable
* the buyer confirms the shipment arrived
* the platform approves submitted evidence

The Approver does not simply report progress. The Approver validates completion.

#### Release = Execution

Release is when funds actually move out of the escrow.

The Release Signer can only release funds after the required approval conditions have been satisfied.

This creates a clear logic chain:

```
Status update / evidence    → Approval        → Release
```

***

### Important Edge Case: Approval Can Happen Before Status Update

In some flows, an Approver may approve a milestone before the Service Provider updates the milestone status.

This means your escrow design should not assume that status always comes before approval.

Instead, treat status and approval as related but separate pieces of state.

The release condition should depend on the required approval logic, not only on a text status.

***

### Step 4: Assign Roles

Every Trustless Work escrow includes a role configuration. Roles determine which address can perform which action.

Current core roles include:

| Role             | Main responsibility                                                                               |
| ---------------- | ------------------------------------------------------------------------------------------------- |
| Service Provider | Updates milestone status and progress                                                             |
| Approver         | Validates milestone completion                                                                    |
| Platform Address | Can receive platform fees and may manage configuration before funding depending on implementation |
| Release Signer   | Executes fund release after approval conditions are met                                           |
| Dispute Resolver | Handles disputes or exception flows when flagged                                                  |
| Receiver         | Receives released funds                                                                           |
| Issuer           | He who deploys the contract. Has no powers over the contract                                      |
| Depositor        | Funds the escrow but does not automatically receive contract permissions                          |
| Observer         | Coming in a future version; tracks escrows without acting on them                                 |

Roles are assigned to addresses.

Only the address assigned to a role can perform the actions allowed for that role.

***

### Role Capability Overview

| Role             | Can update status? |  Can approve? | Can raise dispute? | Can resolve dispute? | Can release funds? | Receives funds? | Notes                                    |
| ---------------- | -----------------: | ------------: | -----------------: | -------------------: | -----------------: | --------------: | ---------------------------------------- |
| Service Provider |                Yes |            No |                Yes |                   No |                 No |              no | Updates milestone progress               |
| Approver         |        No required |           Yes |                Yes |                   No |                 No |              no | Validates milestone completion           |
| Platform Address |     Before funding | No by default |      No by default |        No by default |      No by default |   Fee recipient | Can make changes before escrow is funded |
| Release Signer   |        No required |   No required |                 No |                   No |                Yes |              no | Releases only when conditions allow      |
| Dispute Resolver |        No required | Case-specific |        No required |                  Yes |      Case-specific |              No | Arbitrates and can re-route funds        |
| Receiver         |      No by default |    Usually no |      No by default |                   No |                 No |             Yes | Final destination of released funds      |
| Issuer           |                 No |            No |                 No |                   No |                 No |              No | Has no powers over the contract          |
| Depositor        |                 No |            No |                 No |                   No |                 No |              No | Incoming transactions are indexed        |
| Observer         |                 No |            No |                 No |                   No |                 No |              No | Future tracking role                     |

***

### Step 5: Define Escrow Properties

Roles are only part of the escrow design.

An escrow also includes properties that describe what the escrow is, how it should be indexed, what asset is used, and what state it is in.

Common escrow properties include:

| Property                     | Description                                                                                                          |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| Escrow ID / Contract Address | On-chain identifier of the escrow contract. Also used as the deposit address                                         |
| Engagement ID                | Configurable external identifier used to connect the escrow with an invoice, order, project, or external system      |
| Title                        | Human-readable title of the escrow                                                                                   |
| Description                  | Explanation of why the escrow exists                                                                                 |
| Roles                        | Addresses assigned to permissions such as status updates, approvals, releases, dispute resolution, and fee reception |
| Milestones                   | Actions, deliverables, or conditions that must be completed                                                          |
| Amount                       | Total amount locked or expected in the escrow                                                                        |
| Platform Fee                 | Optional configurable fee for the platform or application                                                            |
| Trustline / Asset            | The asset used in the escrow, such as USDC or another Stellar-issued token                                           |
| Flags                        | State indicators such as disputed, released, or resolved                                                             |

These properties help platforms connect the on-chain escrow with real-world workflows.

***

### Step 6: Choose Your Escrow Type

Trustless Work currently supports two main escrow types:

1. **Single-Release Escrow**
2. **Multi-Release Escrow**

Both use the same core idea: funds are held until defined conditions are met.

The difference is how funds are released.

***

### Single-Release Escrow

A Single-Release Escrow releases funds once.

It can contain multiple milestones, but all required milestones must be approved before the final release happens.

Typical structure:

```
Payer → Escrow → Receiver
```

Typical flow:

```
Create escrow
Fund escrow
Update milestone 1
Approve milestone 1
Update milestone 2
Approve milestone 2
Release full amount
Close escrow
```

Best for:

* deposits
* one-off jobs
* simple deliveries
* full project completion
* marketplace purchases
* final delivery before payment

Key characteristics:

| Dimension       | Single-Release Escrow                                   |
| --------------- | ------------------------------------------------------- |
| Release pattern | One final payout                                        |
| Milestones      | Can have multiple milestones                            |
| Receiver        | Usually one receiver                                    |
| Approval logic  | All required milestones must be approved before release |
| Complexity      | Lower                                                   |

***

### Multi-Release Escrow

A Multi-Release Escrow releases funds progressively.

Each milestone can have its own payout, and each payout can potentially go to a different receiver.

Typical structure:

```
Payer → Escrow → Milestone 1 Receiver
              → Milestone 2 Receiver
              → Milestone 3 Receiver
```

Typical flow:

```
Create escrow
Fund escrow
Update milestone 1
Approve milestone 1
Release milestone 1 funds
Update milestone 2
Approve milestone 2
Release milestone 2 funds
Close escrow
```

Best for:

* grants
* bounties
* milestone-based funding
* phased projects
* contributor payments
* multi-vendor projects
* long-running service agreements

Key characteristics:

| Dimension       | Multi-Release Escrow                      |
| --------------- | ----------------------------------------- |
| Release pattern | Multiple payouts                          |
| Milestones      | Each milestone can have its own release   |
| Receiver        | Can support multiple receivers            |
| Approval logic  | Each milestone can be approved separately |
| Complexity      | Higher                                    |

***

### Single-Release vs Multi-Release

| Question                                            | Use Single-Release | Use Multi-Release |
| --------------------------------------------------- | ------------------ | ----------------- |
| Do funds release once or progressively?             | Once               | Progressively     |
| Are there multiple receivers?                       | Usually no         | Often yes         |
| Does each milestone need its own payout?            | No                 | Yes               |
| Should all milestones be approved before payment?   | Yes                | Not necessarily   |
| Is the workflow simple?                             | Yes                | More complex      |
| Is the workflow grant-like, bounty-like, or phased? | Sometimes          | Usually           |

***

### Step 7: Understand The Lifecycle

The escrow lifecycle describes how an escrow moves from configuration to completion.

Canonical lifecycle:

```
Design
  → Initiation
    → Funding
      → Milestone Updates
        → Approval
          → Release
            → Closure
```

#### 1. Design

Map parties, fund direction, roles, milestones, release conditions, and escrow type.

#### 2. Initiation

Create and configure the escrow.

This includes:

* roles
* milestones
* amount
* asset
* receiver
* platform fee
* engagement ID
* metadata

#### 3. Funding

The payer deposits funds into the escrow.

Possible funding states include:

* unfunded
* partially funded
* fully funded

#### 4. Milestone Updates

The Service Provider or Milestone Marker updates the milestone status.

This creates visibility into progress.

#### 5. Approval

The Approver validates whether the milestone condition was met.

Approval is the key validation step before release.

#### 6. Release

The Release Signer executes the release of funds after approval conditions are met.

In a Single-Release Escrow, this usually happens once.

In a Multi-Release Escrow, this can happen milestone by milestone.

#### 7. Closure

The escrow reaches a terminal state.

Possible terminal states include:

* completed
* cancelled
* refunded
* disputed
* resolved

***

### Design Checklist

Before creating an escrow, answer these questions:

* Who funds the escrow?
* Who receives funds?
* Is there one receiver or multiple receivers?
* Who updates milestone status?
* Who approves milestone completion?
* Who signs the release?
* Is payment released once or by milestone?
* What asset is used?
* What platform fee applies?
* What external system should this escrow connect to?
* What happens if a milestone is not approved?
* What happens if the wrong party is assigned a role?
* Does this use case require dispute resolution?

***

### Example: Marketplace Service Payment

A client wants to pay a freelancer after a project is completed.

Suggested design:

| Element          | Example                                                         |
| ---------------- | --------------------------------------------------------------- |
| Payer            | Client                                                          |
| Receiver         | Freelancer                                                      |
| Service Provider | Freelancer                                                      |
| Approver         | Client                                                          |
| Release Signer   | Client or platform-controlled signer                            |
| Platform Address | Marketplace fee address                                         |
| Escrow Type      | Single-Release or Multi-Release depending on project complexity |

Simple version:

```
Client funds escrow
Freelancer completes work
Freelancer marks milestone as completed
Client approves
Release signer releases funds to freelancer
Marketplace receives fee
```

***

### Example: Grant Tranche Payment

A foundation wants to release funding progressively after deliverables are completed.

Suggested design:

| Element          | Example                             |
| ---------------- | ----------------------------------- |
| Payer            | Foundation or sponsor               |
| Receiver         | Grantee                             |
| Service Provider | Grantee                             |
| Approver         | Grant reviewer or committee         |
| Release Signer   | Foundation signer or program signer |
| Platform Address | Program fee address                 |
| Escrow Type      | Multi-Release                       |

Simple version:

```
Foundation funds escrow
Grantee submits deliverable 1
Reviewer approves deliverable 1
Release signer releases tranche 1
Grantee submits deliverable 2
Reviewer approves deliverable 2
Release signer releases tranche 2
```

***

### Example: Security Deposit

A renter deposits funds that should be held until the rental condition is complete.

Suggested design:

| Element          | Example                                                 |
| ---------------- | ------------------------------------------------------- |
| Payer            | Renter                                                  |
| Receiver         | Renter, landlord, or both depending on outcome          |
| Service Provider | Property manager or platform                            |
| Approver         | Property manager, landlord, renter, or neutral reviewer |
| Release Signer   | Platform-controlled signer or agreed signer             |
| Platform Address | Deposit platform fee address                            |
| Escrow Type      | Single-Release or conditional flow                      |

Simple version:

```
Renter funds escrow
Deposit remains locked
Condition is reviewed
Approver validates outcome
Release signer releases funds according to the result
```

***

### How To Think About Trustless Work

Trustless Work is not only an escrow application.

It is infrastructure for programmable transaction coordination.

Use it when your product needs to answer:

> What must happen before funds move?

If the answer involves multiple parties, milestones, approvals, or release conditions, Trustless Work can help you encode that logic into a smart escrow.

***

### Next Steps

Now that you understand the escrow design model:

1. Define [Escrow Properties](/trustless-work/introduction/technology-overview/what-does-a-smart-escrow-look-like)
2. Choose Your[ Escrow Type](/trustless-work/introduction/technology-overview/escrow-types)
3. Assign [Roles](/trustless-work/introduction/technology-overview/roles-in-trustless-work)
4. Follow the [Lifecycle](/trustless-work/introduction/technology-overview/escrow-lifecycle)
5. Integrate through the [API](/trustless-work/api-rest/introduction), [SDK](/trustless-work/escrow-react-sdk/introduction), or [Blocks](/trustless-work/escrow-blocks-sdk/introduction)

***


# Roles in Trustless Work

Let's understand what each role represents!

Roles define who can do what inside a Trustless Work escrow.

Anyone can deposit funds into an escrow. But only addresses with assigned roles can update milestones, approve work, release funds, or resolve disputes.

This is what makes Trustless Work escrows programmable.

Instead of assuming that one platform, company, or person controls everything, each escrow explicitly defines the addresses responsible for each action.

A good role configuration answers:

> Who must do what before money can move?

***

<figure><img src="/files/oUi0z4Hjn9kUZhoW0fDb" alt=""><figcaption><p>Roles are marked in black</p></figcaption></figure>

***

### Why Roles Matter

An escrow is a coordination system.

Different parties may need different powers:

* one party funds the escrow
* one party performs the work
* one party updates milestone status
* one party validates completion
* one party releases funds
* one party receives the funds
* one party resolves disputes
* one platform receives a fee

Trustless Work separates these responsibilities into roles.

This makes the escrow easier to reason about, safer to configure, and more flexible across use cases.

***

### Role-Based Permissions

Every escrow includes a roles object.

Each role is assigned to an address.

Only the address assigned to that role can perform the actions associated with that role.

For example:

* only the **Service Provider** can update milestone status
* only the **Approver** can approve milestones
* only the **Release Signer** can release funds
* only the **Dispute Resolver** can resolve disputes
* the **Receiver** receives funds after release
* the **Platform Address** receives platform fees and can update escrow details before funding

This role-based model allows platforms to design different trust flows without writing custom smart contracts from scratch.

***

### Core Roles

### 1. Service Provider

The Service Provider is responsible for delivering the product, service, milestone, or outcome defined in the escrow.

This role usually represents the party doing the work.

#### What the Service Provider can do

* change milestone status
* add evidence or proof of delivery
* raise a dispute

#### Examples

| Use case            | Service Provider                             |
| ------------------- | -------------------------------------------- |
| Marketplace payment | Seller, freelancer, vendor, or contractor    |
| Project milestones  | Contractor or project team                   |
| Payouts             | Contributor, vendor, or milestone owner      |
| Crowdfunding        | Company or campaign owner updating progress  |
| Compliance flow     | Compliance team marking a check as completed |

#### Design note

The Service Provider communicates progress.

They do not automatically approve their own work.

In most flows:

```txt
Service Provider updates status
Approver validates completion
Release Signer releases funds
```

***

### 2. Approver

The Approver validates that a milestone has actually been completed.

This role is responsible for signing off on completion before funds can be released.

#### What the Approver can do

* sign the approval of a milestone
* raise a dispute if work is not satisfactory

#### Examples

| Use case            | Approver                                            |
| ------------------- | --------------------------------------------------- |
| Marketplace payment | Buyer, client, or platform reviewer                 |
| Project milestones  | Client, project owner, or reviewer                  |
| Payouts             | Program reviewer, maintainer, or platform admin     |
| Security deposit    | Host, property manager, renter, or neutral reviewer |
| Crowdfunding        | Platform or campaign reviewer                       |

#### Design note

Approval is not the same as a status update.

A status update communicates progress.

Approval validates that the agreed condition has been met.

In some flows, the Approver may approve before the Service Provider updates the status. The important point is that approval should remain an explicit validation action.

***

### 3. Release Signer

The Release Signer triggers the actual release of funds once the required approvals are in place.

This role is responsible for executing payment movement.

#### What the Release Signer can do

* release funds after all milestones are approved in a Single-Release Escrow
* release funds for each approved milestone in a Multi-Release Escrow
* raise a dispute if there is disagreement at the release stage

#### Examples

| Use case            | Release Signer                                                  |
| ------------------- | --------------------------------------------------------------- |
| Marketplace payment | Buyer, platform signer, or authorized release address           |
| Project milestones  | Client, platform signer, or project owner                       |
| Payouts             | Platform signer, treasury signer, or authorized release address |
| DAO bounty          | DAO signer or authorized contributor payment signer             |
| Security deposit    | Platform-controlled signer or agreed release authority          |

#### Design note

The Release Signer executes the release.

The Release Signer should not be confused with the Approver.

In simple flows, the same address may be both Approver and Release Signer. In more sensitive flows, those roles should be separated.

Normal release flow:

```
Status update  → Approval    → Release
```

***

### 4. Receiver

The Receiver is the final destination of released funds.

This role receives funds once the escrow conditions are met and release is triggered.

#### What the Receiver can do

* receive funds once release is triggered

#### Examples

| Use case            | Receiver                                                        |
| ------------------- | --------------------------------------------------------------- |
| Marketplace payment | Seller, freelancer, vendor, or contractor                       |
| Project milestones  | Same contractor or project team across milestones               |
| Payouts             | Different contributor, vendor, or team per milestone            |
| Crowdfunding        | Company receiving milestone-based funding                       |
| Security deposit    | Renter, host, or other final recipient depending on the outcome |

#### Design note

The Receiver is not automatically the Service Provider.

In many cases, they are the same party.

For example, a freelancer can be both:

```
Service Provider = freelancerReceiver = freelancer wallet
```

But in other cases, they may be different.

Example:

```
Service Provider = project managerReceiver = company treasury
```

***

### 5. Dispute Resolver

The Dispute Resolver steps in when parties disagree or when something goes wrong.

This is a core role in the Trustless Work role model.

#### What the Dispute Resolver can do

* resolve disputes by redirecting funds

#### Examples

| Use case            | Dispute Resolver                                        |
| ------------------- | ------------------------------------------------------- |
| Marketplace payment | Marketplace, platform, or neutral resolver              |
| Project milestones  | Arbitrator, project admin, or platform reviewer         |
| Payouts             | Program admin, maintainer, or governance process        |
| Security deposit    | Platform, property manager, or neutral dispute resolver |
| Crowdfunding        | Campaign platform or independent reviewer               |

#### Design note

The Dispute Resolver should be configured intentionally.

This role has important authority because it can affect where funds go when a dispute is raised.

A dispute is not part of every normal escrow path, but the Dispute Resolver role exists so the escrow has a defined resolution authority if conflict happens.

Disputed flow:

```
Dispute raised  → Dispute Resolver reviews    → Funds are redirected or resolved
```

***

### 6. Platform Address

The Platform Address represents the platform or application integrating Trustless Work.

This role is usually used for platform fees and pre-funding configuration changes.

#### What the Platform Address can do

* collect platform fees automatically
* update escrow details while the escrow has not been funded

#### Examples

| Use case            | Platform Address                                  |
| ------------------- | ------------------------------------------------- |
| Marketplace payment | Marketplace fee address                           |
| Project milestones  | SaaS platform or infrastructure fee address       |
| Payouts             | Program, bounty, or treasury platform fee address |
| Crowdfunding        | Crowdfunding platform fee address                 |
| Security deposit    | Rental platform fee address                       |

#### Design note

The Platform Address is not the same thing as the Receiver.

The Platform Address receives the platform fee.

The Receiver receives the escrow payout.

Example:

```
Receiver = freelancerPlatform Address = marketplace fee wallet
```

Also, fee collection should not be confused with full control over funds. The Platform Address can update escrow details before funding, but once funds are locked, the escrow flow should follow the role and lifecycle rules.

***

### Other Addresses You May See

Some addresses may interact with the escrow or appear in indexed data, but they do not have the same action permissions as the core roles above.

***

### Issuer

The Issuer has no powers over the contract.

This address may be present because of how assets, contracts, or metadata are represented, but it does not control escrow actions.

#### Can perform

* no escrow actions

***

### Depositor

The Depositor is any address that sends funds into the escrow.

Every incoming transaction to the escrow is indexed.

However, depositing funds does not automatically give that address permissions inside the escrow.

#### Can perform

* deposit funds

#### Cannot automatically perform

* update milestones
* approve milestones
* release funds
* resolve disputes

#### Design note

This distinction matters.

A wallet can fund an escrow without becoming the Approver, Release Signer, or Receiver.

***

### Observer

Observer is planned for a future version.

An Observer is an address that wants to track an escrow without acting on it.

#### Intended purpose

* observe escrow activity
* make tracking easier by role
* support dashboards, notifications, and transparency use cases

#### Can perform

* no escrow actions

***

### Status, Approval, Dispute, and Release Are Different

Do not collapse these actions into one concept.

| Concept        | Role usually responsible                      | Meaning                  |
| -------------- | --------------------------------------------- | ------------------------ |
| Status update  | Service Provider                              | Communicates progress    |
| Approval       | Approver                                      | Validates completion     |
| Dispute        | Service Provider, Approver, or Release Signer | Signals disagreement     |
| Resolution     | Dispute Resolver                              | Resolves dispute outcome |
| Release        | Release Signer                                | Moves funds              |
| Payout         | Receiver                                      | Receives funds           |
| Fee collection | Platform Address                              | Receives platform fee    |

This distinction is central to escrow design.

***

### Role Capability Matrix

| Role             | Update milestone status | Add evidence  | Approve milestone | Raise dispute | Resolve dispute | Release funds | Receive payout | Receive platform fee | Update before funding |
| ---------------- | ----------------------- | ------------- | ----------------- | ------------- | --------------- | ------------- | -------------- | -------------------- | --------------------- |
| Service Provider | Yes                     | Yes           | No                | Yes           | No              | No            | Sometimes      | No                   | No                    |
| Approver         | No                      | No            | Yes               | Yes           | No              | No            | Usually no     | No                   | No                    |
| Release Signer   | No                      | No            | No                | Yes           | No              | Yes           | Usually no     | No                   | No                    |
| Receiver         | No                      | No            | No                | No            | No              | No            | Yes            | No                   | No                    |
| Dispute Resolver | No                      | No            | Case-specific     | No            | Yes             | Case-specific | No             | No                   | No                    |
| Platform Address | No by default           | No by default | No by default     | No by default | No by default   | No by default | No             | Yes                  | Yes                   |
| Issuer           | No                      | No            | No                | No            | No              | No            | No             | No                   | No                    |
| Depositor        | No                      | No            | No                | No            | No              | No            | No             | No                   | No                    |
| Observer         | No                      | No            | No                | No            | No              | No            | No             | No                   | No                    |

***

### How Roles Interact

In a normal escrow flow:

```
1. Depositor funds the escrow2. Service Provider updates milestone status3. Approver validates the milestone4. Release Signer releases the funds5. Receiver receives the payout6. Platform Address receives the platform fee
```

If something goes wrong:

```
1. Service Provider, Approver, or Release Signer raises a dispute2. Dispute Resolver reviews the situation3. Dispute Resolver resolves the dispute4. Funds are released, redirected, or resolved according to the escrow logic
```

***

### Role Mapping By Use Case

### Marketplace Payment

Use case: **Single-release escrow**

| Role             | Example                                               |
| ---------------- | ----------------------------------------------------- |
| Depositor        | Buyer or client                                       |
| Service Provider | Seller, freelancer, or vendor                         |
| Approver         | Buyer, client, or platform reviewer                   |
| Release Signer   | Buyer, platform signer, or authorized release address |
| Receiver         | Seller, freelancer, or vendor                         |
| Dispute Resolver | Marketplace, platform, or neutral resolver            |
| Platform Address | Marketplace fee address                               |

Best for:

* one buyer
* one provider
* one final payout
* simple delivery confirmation

***

### Project Milestones

Use case: **Multi-release escrow, same receiver**

| Role             | Example                                            |
| ---------------- | -------------------------------------------------- |
| Depositor        | Client, sponsor, or project owner                  |
| Service Provider | Contractor, project team, or vendor                |
| Approver         | Client, reviewer, or project owner                 |
| Release Signer   | Client, platform signer, or authorized signer      |
| Receiver         | Same contractor, team, or vendor across milestones |
| Dispute Resolver | Platform, neutral resolver, or assigned resolver   |
| Platform Address | Platform or infrastructure fee address             |

Best for:

* phased projects
* milestone-based contracts
* grants to one team
* implementation work
* service agreements paid over time

***

### Payouts

Use case: **Multi-release escrow, multiple receivers**

| Role             | Example                                                          |
| ---------------- | ---------------------------------------------------------------- |
| Depositor        | Sponsor, platform, organization, or treasury                     |
| Service Provider | Contributor, vendor, team, or milestone owner                    |
| Approver         | Program reviewer, maintainer, client, or platform admin          |
| Release Signer   | Platform signer, treasury signer, or authorized release address  |
| Receiver         | Different receiver per milestone                                 |
| Dispute Resolver | Platform, neutral resolver, program admin, or governance process |
| Platform Address | Program, bounty, or platform fee address                         |

Best for:

* bounties
* contributor payouts
* multi-vendor projects
* hackathon rewards
* ecosystem incentive programs
* grants with multiple teams

***

### Common Role Combination Patterns

The same address can sometimes hold multiple roles.

This should be done intentionally.

#### Common combinations

| Combination                         | When it makes sense                                     | Risk                                               |
| ----------------------------------- | ------------------------------------------------------- | -------------------------------------------------- |
| Service Provider + Receiver         | A freelancer performs work and receives payment         | Low, common pattern                                |
| Depositor + Approver                | A client funds and approves the work                    | Common, but client can delay approval              |
| Approver + Release Signer           | Simple workflows where the approver also releases funds | Concentrates validation and execution authority    |
| Platform Address + Dispute Resolver | Platform handles fees and dispute resolution            | Platform gains significant influence over outcomes |

#### Risky combinations

| Combination                    | Why it is risky                                                          |
| ------------------------------ | ------------------------------------------------------------------------ |
| Service Provider + Approver    | Party can approve its own work                                           |
| Receiver + Release Signer      | Receiver may be able to trigger payment to itself if safeguards are weak |
| Platform Address + Receiver    | Confuses fee recipient with payout recipient                             |
| One address holding every role | Recreates centralized custody-like control                               |

***

### Role Design Checklist

Before deploying an escrow, confirm:

* Who funds the escrow?
* Who updates milestone status?
* Who approves completion?
* Who can raise a dispute?
* Who resolves disputes?
* Who releases funds?
* Who receives payout?
* Who receives platform fees?
* Is the Receiver different from the Platform Address?
* Is the Service Provider also the Receiver?
* Is the Approver also the Release Signer?
* Should any role be separated for safety?
* Does the use case require a neutral Dispute Resolver?
* Are you using Single-Release or Multi-Release?
* Are there multiple receivers?


# Escrow Properties

An escrow is just structured data — a JSON body that defines how funds are held, released, and tracked. Each property tells the contract who does what, when funds move, and under which conditions.

TLDR:&#x20;

* *Single-Release → all milestones must be approved for one payout.*
* *Multi-Release → each milestone unlocks its own payout.*

Below we break down the **core properties** of every escrow, and then highlight the **differences between Single-Release and Multi-Release.**

<figure><img src="/files/cTNpevts5QEwnNz6bvCH" alt=""><figcaption><p>Single Release escrow</p></figcaption></figure>

### Core Structure

* **Escrow ID**\
  The on-chain identifier of the contract (also the deposit address). This is where funds are actually sent and locked.
* **Engagement ID & Title**\
  Configurable strings that help you identify the escrow in your own system — for example, linking it to an invoice, project ID, or marketplace order.
* **Description**\
  Human-readable explanation of the escrow’s purpose. Useful for context in dashboards, audits, or dispute resolution.
* **Roles**\
  Every escrow defines who can act on it:
  * *Approver* → validates milestone completion
  * *Service Provider* → delivers the work
  * *Platform Address* → the platform itself, able to take fees or adjust config before funding
  * *Release Signer* → executes the release of funds
  * *Dispute Resolver* → arbitrates conflicts, can re-route funds
  * *Receiver* → final destination of the funds\
    👉 See Roles for full detail.
* **Amount & Platform Fee**
  * **Single-Release**: the total `amount` to be paid once conditions are met, plus an optional `platformFee` percentage sent to the platform.
  * **Multi-Release**: the total amount is distributed across milestones (each milestone defines its own `amount`). The platform fee still applies globally.
* **Trustline**\
  Defines the token being used. This is how Stellar escrows know which asset to accept. Typically USDC, but any Stellar-issued token is supported.
* **Flags**\
  Internal state markers that describe what’s happening:
  * `disputed` → a party raised a dispute
  * `released` → funds have already been released
  * `resolved` → a dispute has been settled
  * `approved` (Multi-Release only) → milestone has been approved by approver

***

### Milestones

Milestones define *what must be completed to unlock funds.*

* **Single-Release Escrow**
  * You can define **one or many milestones**, but the release is **all-or-nothing**.
  * Funds are only released **once all milestones are approved**.
  * Each milestone tracks:
    * `description` → what’s being delivered
    * `status` → any type of status
    * `approve` → true or false
    * `evidence` (optional) → proof of delivery
* **Multi-Release Escrow**
  * Each milestone has the same properties as the single release, plus its own amount and flags.
  * When a milestone is approved, its funds can be released without waiting for others.
  * Milestones include:
    * `amount` → how much is unlocked upon approval
    * `description` → what’s being delivered
    * `status` → any type of status
    * `flags` → released, disputed, resolved and approve
    * `receiver` → final destination of the funds

This structure allows a project to fund and release in **phases**, not all at once.

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

***

### Putting It Together

* **Single-Release** = one payout, triggered when *all milestones are approved*.\
  Amount + release & dispute flags live at the **top level** of the escrow.
* **Multi-Release** = multiple payouts, each milestone has its own amount and flags.\
  The total escrowed amount is distributed across milestones.

Both share the same core structure — IDs, roles, description, trustline, and platform fee.\
The difference is:

* **Single-Release** → milestones are “checkpoints” for one big release.
* **Multi-Release** → milestones are “tranches,” each tied to its own release.

***

### 🚀 Next Steps

* Choose [Escrow Type](/trustless-work/introduction/technology-overview/escrow-types)
* Assign [Roles](/trustless-work/introduction/technology-overview/roles-in-trustless-work)
* Follow [Lifecycle Phases](/trustless-work/introduction/technology-overview/escrow-lifecycle)
* Test configs in [deploy in dApp](/trustless-work/oss-dapps/backoffice)


# Escrow Types

Trustless Work supports multiple escrow types, each tailored for different workflows. Whether you're building a marketplace, a grant platform, or a gig app, choosing the right escrow logic helps you balance simplicity, flexibility, and trust.

***

### Single-Release Escrow

A Single-Release Escrow holds funds until *all* milestones (verifiable checkpoints, like "design done" or "code deployed") are completed and approved. Only then is the *entire* amount released in one go. It’s built for projects where trust builds across multiple steps but payout happens once.

**Build it like this:**

1. **Deposit:** Funds are locked upfront by any party (e.g., a client) via a Stellar wallet.
2. **Milestone Completion:** The Service Provider (e.g., a freelancer) marks each milestone complete (e.g., "Logo delivered," "Site live").
3. **Approval & Release:** The Approver (e.g., the client) verifies *all* milestones. Once all are signed off, the Release Signer (e.g., the platform) releases the full amount to the Receiver, minus any Platform fee.

<figure><img src="/files/QoH0ylFpAiJVJXplhmIX" alt="single-release"><figcaption></figcaption></figure>

**Example:** A freelancer on a marketplace delivers a website (milestones: wireframe, design, launch). The buyer (Approver) confirms all are done, and the platform (Release Signer) releases the full payment.

***

### Multi-Release Escrow

A Multi-Release Escrow releases funds incrementally as each milestone is completed and approved. It’s designed for staged projects where trust and payments build step-by-step, reducing risk.

**Build it like this:**

1. **Deposit:** Funds are deposited upfront or in parts via Stellar wallets.
2. **Milestone Completion & Review:** The Service Provider (e.g., a DAO contributor) marks each milestone complete (e.g., "Prototype built"). The Approver (e.g., DAO voters) reviews each.
3. **Incremental Release:** For each approved milestone, the Release Signer (e.g., the platform) releases that milestone’s portion of funds to the Receiver. Dispute Resolvers handle conflicts, adjusting amounts or canceling if needed. (Note: Per-milestone payouts are coming, per doc.)

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

**Example:** A DAO funds a developer for a project (milestones: code v1, v2, v3). Each milestone’s approval releases a portion of stablecoins, with a Dispute Resolver stepping in if voters contest progress.

**Why use it?**

* ✅ Flexible: Pay per milestone, not all at once.

***

| Aspect     | Single-Release                            | Multi-Release          |
| ---------- | ----------------------------------------- | ---------------------- |
| Payouts    | All at once, post all milestones          | Per milestone          |
| Use Case   | Freelance with staged checks              | Grant disbursements    |
| Complexity | Medium (multiple milestones, one release) | High (staged releases) |

### Quick Tips:

* Use **Single-Release** to get started fast.
* Use **Multi-Release** when you need milestone-based control.
* All escrows are **non-custodial**, programmable, and stablecoin-native.

***

### JSON Examples

Here are two minimal JSON snippets that highlight the structural difference between **Single-Release** and **Multi-Release** escrows. These aren’t full schemas, just the essentials so a builder can “see it” at a glance.

***

### 📝 Example: Single-Release (with multiple milestones)

```json
{
  "contractId": "C...ESCROWADDRESS",
  "engagementId": "order-123",
  "title": "Website Development",
  "description": "Build and deliver a marketing website",
  "roles": {
    "approver": "G...CLIENT",
    "serviceProvider": "G...FREELANCER",
    "releaseSigner": "G...SIGNER",
    "platformAddress": "G...PLATFORM",
    "disputeResolver": "G...RESOLVER",
    "receiver": "G...FREELANCER"
  },
  "amount": 1000,
  "platformFee": 0.5,
  "milestones": [
    {
      "description": "Deliver homepage design",
      "status": "Approved",
      "approved": true
    },
    {
      "description": "Deploy full website",
      "status": "Pending",
      "approved": false
    }
  ],
  "flags": {
    "disputed": false,
    "released": false,
    "resolved": false
  },
  "trustline": {
    "address": "G...USDCISSUER",
  }
}
```

👉 Even with multiple milestones, **all must be approved** before the single payout of `1000` USDC is released.

***

### 📝 Example: Multi-Release

```json
{
  "contractId": "C...ESCROWADDRESS",
  "engagementId": "grant-456",
  "title": "Research Grant",
  "description": "Funding project in two phases",
  "roles": {
    "approver": "G...FUNDER",
    "serviceProvider": "G...RESEARCHER",
    "releaseSigner": "G...SIGNER",
    "platformAddress": "G...PLATFORM",
    "disputeResolver": "G...RESOLVER",
  },
  "platformFee": 0.5,
  "milestones": [
    {
      "description": "Submit interim report",
      "amount": 500,
      "status": "Approved",
      "flags": { "approved": true, "released": true, "disputed": false, "resolved": false },
      "receiver": "G...RESEARCHER"
    },
    {
      "description": "Publish final report",
      "amount": 500,
      "status": "Pending",
      "flags": { "approved": false, "released": false, "disputed": false, "resolved": false },
      "receiver": "G...RESEARCHER"
    }
  ],
  "trustline": {
    "address": "G...USDCISSUER",
  }
}
```

👉 Here, each milestone has its own **amount** and **flags**. Funds are released milestone-by-milestone (`500` + `500`).


# Escrow Lifecycle

The escrow lifecycle is the structured flow of actions and responsibilities that secure a transaction. At Trustless Work, we break this into clear phases, ensuring transparency, adaptability, and cons

{% embed url="<https://youtu.be/Dv7ZEmZPxBc>" %}

## Core Phases:

#### **1. Initiation Phase:**

The foundation of the escrow:

* Roles and responsibilities are defined
* Transaction terms (amount, milestones, fees, trustline) are set
* The escrow contract is created on-chain

&#x20;[Learn More](/trustless-work/introduction/technology-overview/escrow-lifecycle/initiation-phase)

#### **2. Funding Phase:**

* Anyone can deposit funds
* Once funded, the escrow is live and ready for milestone tracking

. [Learn More](/trustless-work/introduction/technology-overview/escrow-lifecycle/funding-phase)

#### **3. Milestone Updates Phase:**

* Marked as completed
* Optional evidence or proof can be added
* Provides visibility for review

[Learn More](/trustless-work/introduction/technology-overview/escrow-lifecycle/milestone-status-update)

#### 4. Approval

Milestones are reviewed by the **Approver**.

* Can approve if conditions are met
* Can raise a dispute if unsatisfied

Approval moves the escrow closer to payout.

&#x20;[Learn More](/trustless-work/introduction/technology-overview/escrow-lifecycle/approval-phase)

#### 5. Release

The **Release Signer** authorizes payout.

* **Single-Release** → all milestones must be approved before one payout
* **Multi-Release** → funds are released milestone by milestone

Funds are transferred to the **Receiver**, minus any platform fee.

&#x20;[Lean More](/trustless-work/introduction/technology-overview/escrow-lifecycle/release-phase)

***

### ⚠️ Alternative Phase: Dispute Resolution

If any party raises a dispute, the lifecycle takes a detour:

#### Dispute Resolution

* **Dispute Resolver** steps in to resolve the conflict
* Can redirect funds, adjust milestones, or cancel the escrow
* Outcomes can be:
  * Full refund to client
  * Partial refund
  * No refund (funds go to provider)

[Learn more](/trustless-work/introduction/technology-overview/escrow-lifecycle/dispute-resolution)


# Initiation Phase

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

The **Initiation Phase** is where the escrow takes shape.

You’re not moving money yet — you’re defining the logic that will *govern* how it moves later.

Think of this as the **architecture of trust**: setting the rules, actors, and conditions before anything hits the chain.

&#x20;**Participants and Roles**

In the initiation phase key roles are assigned to specific parties. These roles determine responsibilities and actions throughout the transaction.

***

### 🎭 Define the Roles

Every escrow is role-based — meaning only specific addresses can perform specific actions.

You can [read more about roles here → Roles in Trustless Work](https://chatgpt.com/g/g-p-6849f5b035a88191b0faae5593cab5e8-tw-content/c/690d2534-f8b8-832d-bcc2-dc3108a4f1a3).

During initiation, you assign which addresses will act as:

* **Milestone Marker (Service Provider)** — delivers work and marks milestones as done
* **Approver** — validates each milestone and can raise disputes
* **Release Signer** — triggers the release of funds once conditions are met
* **Dispute Resolver** — resolves conflicts and reallocates funds
* **Receiver** — the final destination of funds
* **Platform Address** — the address of the platform itself (receives a percentage fee and can adjust configuration before funding)

> 🔑 Roles are permissions, not identities.
>
> The same wallet can hold more than one role, depending on your workflow.

***

### 💰 Decide the Amounts and Milestones

This is where you define **what gets paid, and when**.

* For a **Single-Release escrow**, you’ll have **one total amount** and **one receiver**.
  * The payment only happens once, after all milestones are approved.
  * Example: a one-off design project or security deposit.
* For a **Multi-Release escrow**, you’ll define **multiple milestones**, each with:
  * Its **own amount**
  * Its **own receiver**
  * Its **own flags and status**

This structure allows you to fund once and pay multiple parties or stages over time.

> 💡 You can even add milestones later — turning one escrow into an ongoing contract.

***

### 🪙 Select the Trustline (Asset Configuration)

On Stellar, every token (like USDC) is identified by its **issuer address**.

To hold that token, your wallet must explicitly “trust” that issuer — this is called a **Trustline**.

* When you create an escrow, you must define which **trustline** (asset) it will hold.

  Example: `GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5` = USDC.
* All participating addresses (Approver, Marker, Release Signer, etc.) must have that trustline enabled in their wallet.

  Otherwise, they won’t be able to receive or send that asset.

> ⚠️ Without the trustline set, the transaction will fail — so ensure every role wallet is ready before deployment.

***

### 🧾 Assign the Engagement ID (Reference Tracking)

Every escrow includes an **Engagement ID**, which acts like your external reference number.

It’s a human-readable tag that connects the on-chain escrow to your off-chain logic.

Examples:

* `ORDER_2025_00234`
* `INVOICE_98B-13`
* `DAO_GRANT_ROUND2`

> The Engagement ID is optional for blockchain logic, but essential for indexing and analytics.
>
> It lets platforms query, group, and monitor escrows easily through the API or the viewer.

***

### ⚙️ Configure Platform Fee

Platforms can earn a **Platform Fee** on each escrow.

This fee is taken at release, alongside the protocol’s **0.3% Trustless Work fee**.

* Example:
  * Platform Fee = 1%
  * Trustless Fee = 0.3%
  * Total deduction = 1.3% (automatically split between platform and protocol)

The platform fee is sent to the **Platform Address** defined in the roles.

> 💡 For marketplaces and SaaS platforms, this is a native monetization layer built into the escrow logic — no separate billing flow required.

***

### 📦 Output of the Initiation Phase

At the end of Initiation, you have:

* A **complete schema** defining every role, milestone, fee, and asset
* A **trustline** selected and validated for all participants
* An **engagement ID** linking your escrow to external records
* A **clear understanding** of what needs to happen before any money moves

This is the blueprint.

Once finalized, it’s deployed to the blockchain as an immutable contract.

From here on, every signature, approval, or release event happens *on-chain*.

Also, you should be able to view the escrow and it’s configuration on the escrow viewer or on Stellar expert.

***


# Funding Phase

<figure><img src="/files/4t13nr0wFrQmJQeHNDEQ" alt=""><figcaption></figcaption></figure>

## Phase 2 — Funding (When Logic Meets Capital)

Once an escrow is deployed, it becomes **fundable** — meaning any authorized wallet can deposit assets into it.\
This is where trust becomes tangible: the logic you set in the Initiation Phase now holds real value.

The **Funding Phase** signals the start of the agreement in motion.\
It turns the escrow from an empty container of logic into a live, capital-backed contract.

***

### 💸 Two Ways to Fund

Every escrow has an **Escrow ID** (also called **Contract ID**).\
Both terms refer to the same on-chain address — where funds are actually held.

You can fund an escrow in **two main ways**:

1. **Direct Deposit** — Send funds manually to the escrow’s ID using any Stellar wallet.
   * This method is simple and works universally.
   * However, deposits made this way may not automatically trigger indexation events, so if you’re building analytics or dashboards, you’ll need to handle those deposits separately.
2. **Using the “Fund Escrow” Endpoint** — via the Trustless Work API or dApp.
   * This option generates and signs the transaction from your connected wallet (e.g., Freighter).
   * It also emits a **Deposit Event** on-chain, making it easier for our indexer (and your platform) to track and verify deposits automatically.
   * This is the method we recommend — it’s what powers the “Fund” buttons in our Backoffice and Demo dApps.

> ⚡ In short:
>
> * Direct deposits **work** for any wallet or integration.
> * The API endpoint **tracks** them better for dashboards, automation, and future reconciliations.

***

### 🎯 The Amount and the Balance

When you deployed your escrow, you defined a **target amount** — that’s your goal.\
It’s used to calculate whether the escrow is:

* **Fully Funded** – the on-chain balance matches the target amount
* **Partially Funded** – the balance is lower than expected
* **Overfunded** – extra deposits were made

What you see on-chain is the **balance**, which is dynamic:

* It increases when deposits are made.
* It decreases when funds are released.
* It always reflects the escrow’s current real-time state.

> 💡 The target `amount` is static — it represents intent.\
> The `balance` is live — it represents reality.

***

### 🪙 Compatible Wallets and Assets

Funds can come from any wallet that supports the **trustline** you defined during initiation.\
The most common setup is **USDC on Stellar**, but any asset with a valid trustline works.

We recommend using **non-custodial wallets** for deposits — especially **Freighter**, our default integration.

> ⚠️ **Important note:**\
> Some custodial exchanges (like Binance) don’t yet support sending directly to contract addresses.\
> Withdrawals may fail or get flagged as invalid.\
> Always test deposits from a non-custodial wallet first.

***

### 🔄 Advanced Integrations (Optional)

If you’re building a product where funds flow in from external users or payment processors — like a marketplace or investment pool — you can integrate **on-ramp services** directly with the escrow.

We’ve tested integrations where on-ramps send USDC straight to an escrow contract, creating a seamless deposit experience.\
Each successful deposit triggers an event that platforms can listen to for **real-time funding status** updates.

> 💬 Builders who want to explore advanced integrations can check out our open-source examples and dApp code on GitHub.\
> We’re continuously experimenting with new funding patterns and wallets to improve this experience.

***

### 📦 Outcome of the Funding Phase

By the end of this phase:

* Your escrow now holds real assets.
* Its balance reflects the amount deposited.
* Events are recorded on-chain for transparency.
* All participants can independently verify the deposit.

You can confirm the escrow’s funded state on:

* 🌐 [**Escrow Viewer**](https://viewer.trustlesswork.com) — for a clear visual of deposits and status
* 🔍 [**Stellar Expert**](https://stellar.expert) — for blockchain-level transaction details

> 💡 Use the Viewer for clarity, Expert for raw transparency.


# Change Milestone Status

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

## Phase 3 — Change Milestone Status (Signaling Progress)

Once the escrow is funded, the work begins.\
This phase is where the **Service Provider** (or *Milestone Marker*) communicates progress to everyone else — by signing an update that changes the milestone’s status.

It’s how the escrow “breathes.”\
Each update becomes a traceable, on-chain proof of what’s happening off-chain.

***

### 🧱 What “Change Milestone Status” Means

Every milestone in an escrow has two types of information:

1. **Structural data** — defined at deployment (title, receiver, amount).
2. **Dynamic status** — updated as work evolves.

The **Change Milestone Status** action updates that dynamic state.\
It’s not limited to pre-set words like *pending* or *done* — your platform defines the vocabulary.

A milestone could move through any flow you design:

* *“Design Started” → “Ready for Review” → “Approved”*
* *“Product Packed” → “In Transit” → “Delivered”*
* *“Pull Request Opened” → “Code Merged” → “Deployed”*

> 💬 **Trustless Work doesn’t impose statuses.**\
> It only ensures that the update comes from the correct role — the Service Provider — and that every change is signed and recorded.

***

### ✍️ Who Can Perform This Action

Only the **Service Provider (Milestone Marker)** can sign milestone status updates.\
This preserves accountability: progress always originates from the party doing the work.

Once signed, the update is broadcast on-chain, and the contract records:

* The **new status label** (a text string defined by your platform)
* An optional **evidence field**

Other participants — Approver, Release Signer, Platform — can view the update but cannot alter it.

***

### 🧾 Adding Evidence

Each update can include an **evidence input**, typically a URL or reference pointing to external proof of progress.

This could be:

* A link to a code repository, pull request, or merge commit
* A delivery receipt, tracking page, or signed document
* A file stored on decentralized storage like IPFS, Filecoin, or Arweave

> 📎 **Note:** Trustless Work doesn’t store media or documents.\
> It only stores the *reference* — keeping the escrow lightweight and privacy-respectful.\
> Platforms decide where evidence lives, and how much they want to display publicly.

***

### 🔁 How Platforms Can Use This

Platforms can build their own workflows on top of this mechanism:

* Display a real-time progress feed on dashboards
* Require specific evidence types before allowing “Approve” actions
* Automate milestone transitions based on external data (e.g., an API confirming delivery)

Each status update becomes part of the escrow’s event history — a transparent, auditable record of progress.

***

### ⚙️ What Changes On-Chain

Every signed update triggers:

* A **Milestone Status Event**, visible on Stellar explorers and in the Escrow Viewer
* A refreshed view of the milestone’s metadata (`status`, `evidence`, and timestamp)

It doesn’t release funds — it just advances the state.\
The **Approval Phase** that follows decides whether payment moves forward or the milestone is disputed.

***

### 📦 Outcome of the Change Milestone Status Phase

By the end of this phase:

* The Service Provider has submitted a new, verifiable progress update.
* The escrow now reflects the most recent milestone status and evidence.
* All participants can see the change on-chain and in the [**Escrow Viewer**](https://viewer.trustlesswork.com).

> This phase transforms subjective progress into verifiable data — one signed update at a time.


# Approval phase

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

## Phase 4 — Approval (Validating Progress and Unlocking Readiness)

After the Service Provider updates a milestone’s status, the **Approver** steps in.\
This is the phase where intent meets validation — the moment a platform or client officially confirms that progress is satisfactory.

Approval is the **green light** that tells the escrow:

> “This milestone has met the conditions. It can now move toward payment.”

***

### 🧾 What Approval Means

Approving a milestone doesn’t move funds yet — it simply updates the milestone’s internal flag:\
`approved: true`

That single flag transforms the milestone from *in progress* to *ready for release*.

It’s a lightweight change in data but a heavy one in meaning — because once approved, the milestone is permanently recorded as validated.\
There’s no “unapprove” function.\
The decision becomes part of the escrow’s history.

***

### 👤 Who Approves

Only the **Approver** — the wallet assigned to that role — can sign the approval.\
This address is often:

* The **buyer** in a freelance contract,
* The **sponsor** in a grant,
* Or the **platform logic** in automated or multi-party flows.

The Approver’s signature confirms that:

1. The milestone has been delivered satisfactorily, and
2. The platform can now safely move toward release.

***

### 🔁 How Approval Works Across Escrow Types

#### **Single-Release Escrow**

* All milestones must be approved before any funds can move.
* Once every milestone carries the `approved: true` flag, the escrow becomes “ready for release.”
* The Release Signer can then execute the payout in one transaction.

#### **Multi-Release Escrow**

* Each milestone has its own approval and release logic.
* Approving one milestone makes *that milestone’s funds* eligible for release, regardless of others.
* This allows multiple, independent approval-release cycles within the same escrow.

> 🧩 **In short:**
>
> * **Single-Release** → approval is collective (all or nothing).
> * **Multi-Release** → approval is modular (one milestone at a time).

***

### 🪶 The Freedom of Approval Timing

Approvals can happen at any moment, regardless of the milestone’s current “status” text.

Even if the Service Provider used a custom status like *“Under Review”* or *“In Transit”*,\
the Approver can sign approval immediately if they’re satisfied.

That flexibility allows each platform to define its own logic — maybe auto-approving after a timer, or requiring manual review before payment.

Once approved:

* The milestone’s `approved` flag turns **true**,
* The escrow recognizes that milestone as complete,
* And it remains approved for the rest of its lifecycle.

***

### 🧩 Relation to Disputes and Release

Approval is also what separates smooth transactions from disputes.\
If the Approver signs, the flow advances to **Release**.\
If they refuse or challenge, the same milestone can instead move into **Dispute Resolution**.

> 🧭 Approval is the fork in the road —\
> One path leads to payment, the other to mediation.

***

### 📦 Outcome of the Approval Phase

By the end of this phase:

* The milestone’s `approved` flag is set to **true**.
* The escrow recognizes that milestone as *ready for release*.
* The approval event is permanently logged on-chain.
* Participants can view the approval in real time through the [**Escrow Viewer**](https://viewer.trustlesswork.com).

> 💡 Approval doesn’t release funds — it unlocks the ability to.\
> It’s the signal that work is accepted, and the escrow can now fulfill its purpose.


# Release phase

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

## Phase 5 — Release (Executing the Payout)

The **Release Phase** is where everything comes together — approvals turn into payouts, and logic turns into money movement.\
This is the only phase that actually *moves funds* out of the escrow and into the hands of the receivers.

It’s also the most restricted phase:

> Only the **Release Signer** can execute the release.

***

### 🔑 Who Can Release Funds

Every escrow designates one address as the **Release Signer**.\
That wallet — and *only* that wallet — can authorize the transfer of funds out of the escrow contract.

Depending on your workflow, this role can be configured in two main ways:

* **As a “push” model** — the platform or a neutral signer triggers the release to the receiver.
* **As a “claim” model** — the receiver *is also* the release signer, meaning they can claim their own funds once approved.

Both options are valid, and each suits a different kind of use case:

| Use Case                           | Release Pattern | Example                                                        |
| ---------------------------------- | --------------- | -------------------------------------------------------------- |
| **Freelance marketplaces**         | Push            | Platform acts as release signer, paying out after approval     |
| **Escrow-based payouts or grants** | Claim           | Receivers themselves trigger withdrawal                        |
| **Automated dApps or DAO tooling** | Push or Claim   | Logic bots or scripts trigger release conditions automatically |

***

### 🧭 What Must Be True Before Release

The escrow enforces strict verification before funds can move.

#### **Single-Release Escrow**

* All milestones must have their `approved` flag set to **true**.
* No milestone can be in dispute.
* Once verified, the contract releases the **entire escrowed amount** (minus fees) to the receiver.

#### **Multi-Release Escrow**

* Only the milestone(s) being released need to be approved.
* Each milestone can be released independently.
* The contract disburses only the approved milestone’s amount to its corresponding receiver.

> 🧩 In essence:
>
> * **Single-Release:** “Release everything.”
> * **Multi-Release:** “Release just this part.”

***

### ⚙️ What Happens When Release is Signed

When the Release Signer executes the transaction:

1. The contract verifies all conditions.
2. It calculates deductions:
   * **Platform Fee** (set during initiation, e.g., 1%)
   * **Trustless Work Fee** (protocol fee, fixed at 0.3%)
3. It transfers the remaining balance to the receiver’s address.
4. It updates the milestone (or entire escrow) with:
   * `released: true`
   * A release transaction hash (visible on-chain).

This event becomes a permanent, auditable record of payout completion.

***

### 💬 Push vs. Claim — Two Faces of Release

#### **Push**

* The Release Signer (platform or operator) sends funds out proactively.
* Ideal for platforms that handle fund flow on behalf of users.
* Provides an extra layer of control and compliance.

#### **Claim**

* The Receiver *is also* the Release Signer.
* They simply “claim” their approved funds directly from escrow.
* Ideal for trust-minimized environments, grants, or bounty-style setups.

> 🧠 Both flows coexist within Trustless Work.\
> The release logic doesn’t care *who* presses the button — only that the signer has permission.

***

### 🌐 Visibility and Traceability

Every release emits a **Release Event** — a blockchain record containing:

* The escrow ID (contract address)
* The milestone(s) released
* The receiver address
* Amount sent
* Platform and protocol fees deducted

You can view these transparently through:

* [**Escrow Viewer**](https://viewer.trustlesswork.com) — human-readable milestone and release records
* [**Stellar Expert**](https://stellar.expert) — raw transaction details for verification and audit trails

***

### 📦 Outcome of the Release Phase

By the end of this phase:

* The approved milestones (or full escrow) have been paid out.
* Platform and Trustless Work fees have been distributed.
* The escrow contract updates its flags (`released: true`) accordingly.
* A complete payout record is available both on-chain and in the Viewer.

> 💡 The Release Phase is where trust becomes settlement —\
> money leaves the neutral zone and reaches its rightful destination.


# Dispute Resolution

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

## Phase 6 — Dispute Resolution (When Trust Meets Judgment)

No matter how well-designed a process is, disagreements happen.\
That’s why every Trustless Work escrow includes a final safeguard: **Dispute Resolution**.

This phase ensures that when parties disagree on delivery or results, funds don’t vanish into uncertainty.\
They stay locked in the escrow until a **Dispute Resolver** decides where they should go.

***

### ⚖️ The Role of the Dispute Resolver

The **Dispute Resolver** is the only address authorized to intervene once a dispute is raised.\
This role represents a **neutral authority** — it can be:

* A **platform’s customer support** team mediating between users
* A **DAO-based arbitration module**
* A **trusted third party or auditor**
* Or, in advanced setups, a **decentralized dispute resolution DAO**

The resolver’s job is to review both sides, look at the evidence, and decide how the locked funds will be distributed.

***

### 🧾 How a Dispute Is Raised

Disputes can be triggered by either:

* The **Service Provider** (e.g., claiming they delivered as promised), or
* The **Approver** (e.g., claiming the work was unsatisfactory).

Once raised:

* The milestone or escrow’s `disputed` flag is set to **true**.
* The contract enters a locked state — meaning **no further releases** can happen until it’s resolved.
* All updates and evidence remain visible on-chain for transparency.

***

### 🧠 How the Resolver Makes a Decision

The Dispute Resolver signs a **resolution transaction** that includes:

1. A **list of addresses and amounts** to re-route the funds to.
2. Optional **evidence** or reasoning (usually an off-chain link or case reference).

> 💡 This flexible format replaces the older binary system (refund or payout).\
> It allows more nuanced outcomes — partial refunds, multi-party settlements, or even new allocations in special cases (like shared credit lines or pooled contributions).

***

### 🔄 Transparency and Traceability

Every resolution is **publicly verifiable** and **immutable**:

* The contract emits a **Resolution Event** containing all the distributions.
* These amounts become part of the escrow’s historical record.
* Anyone can inspect who received what, when, and why.

This creates **transparent, tamper-proof accountability** — essential for platforms that need audit trails, regulatory compliance, or internal oversight.

You can verify resolution details directly in:

* [**Escrow Viewer**](https://viewer.trustlesswork.com) — structured breakdown of resolution outcomes
* [**Stellar Expert**](https://stellar.expert) — raw transaction data and event logs

***

### 👥 Who Plays This Role in Practice

Depending on the ecosystem, the Dispute Resolver can be implemented in different ways:

| Scenario                          | Dispute Resolver                          | Example                                             |
| --------------------------------- | ----------------------------------------- | --------------------------------------------------- |
| **Marketplace or SaaS Platform**  | Platform’s customer support team          | Upwork, Fiverr-style review desk                    |
| **Grants or DAOs**                | Governance contract or arbitration module | Community voting or delegated resolution            |
| **Private Credit & Finance**      | Escrow manager or legal agent             | Adjusts amounts between borrower, lender, guarantor |
| **P2P / Trust-Minimized Systems** | Decentralized arbitration                 | Uses smart contracts or on-chain juries             |

> 🧩 The role is flexible — the key is that the resolver’s actions are traceable, transparent, and signed.

***

### 🪶 Evidence and Off-Chain Storage

Resolvers can attach **evidence** to their decisions — for example:

* Case reports
* Proof of refund agreements
* Links to decentralized storage (IPFS, Arweave, Filecoin)

Trustless Work stores only the **reference** (the URL or hash), not the file itself.\
This keeps the on-chain data light while preserving a full trail of proof.

***

### 📦 Outcome of the Dispute Resolution Phase

By the end of this phase:

* The **Dispute Resolver** has signed and submitted a resolution transaction.
* Funds have been re-routed according to the distribution list.
* The escrow’s `resolved` flag is set to **true**.
* All movements are publicly visible and auditable.

> 💡 The Dispute Phase proves that even in disagreement, trust can remain programmable.\
> No hidden decisions — every outcome is on-chain, traceable, and final.


# Architecture & Design Strategy

#### Building Hybrid — The Power of Decentralized Foundations

Most platforms don’t need to “go fully on-chain.”\
What they need is **programmable trust**—a neutral, verifiable layer that handles what matters most: custody, release logic, and auditability.

That’s what Trustless Work provides.\
We let you decide *how decentralized* you want to go — from a quick no-code back office setup to a fully automated, API-driven architecture.

***

#### ⚙️ How Decentralization Fits In

Traditional escrows live in someone else’s infrastructure — you trust the platform or a third-party agent to hold and release funds.\
In Trustless Work, the **escrow itself is the infrastructure**.\
Each one is an independent smart contract that holds logic, roles, and balances directly on the Stellar blockchain.

This design gives you:

* **Transparency** — anyone can verify the escrow in real time.
* **Composability** — you can plug this logic into your own stack.
* **Control** — you decide how much you abstract or automate.

***

#### 🧩 The Trustless Work Architecture

| Layer                        | Tool                                   | What It Does                                                      | Typical User                 |
| ---------------------------- | -------------------------------------- | ----------------------------------------------------------------- | ---------------------------- |
| **1. Smart Contract Layer**  | **Soroban Escrow Contract**            | Core logic for milestones, roles, and fund releases.              | Everyone — the foundation    |
| **2. Integration Layer**     | **Escrow API & SDK**                   | Programmatic control from your backend or frontend.               | Developers                   |
| **3. Interaction Layer**     | **Back Office dApp**                   | Visual control panel for creating, funding, and managing escrows. | Ops, admins, non-dev teams   |
| **4. Transparency Layer**    | **Escrow Viewer**                      | Public, read-only audit tool for contracts on testnet or mainnet. | Compliance, users, investors |
| **5. Experimentation Layer** | **Demo Lab dApp**                      | Sandbox for learning and rapid testing.                           | Builders, hackathons         |
| **6. Automation Layer**      | **AI Agents / Webhooks (coming soon)** | Automate milestone checks, approvals, or payouts.                 | Advanced users               |

Each tool works **independently**, but connects seamlessly through the same escrow contracts and API logic.

***

#### 🧱 Hybrid Implementation Models

Not every company will deploy the entire stack.\
That’s why Trustless Work is **hybrid by design** — you can start manual, add automation later, or plug in your own UI at any time.

**1. Back Office–First**

Launch without writing code.\
Use the Back Office to deploy escrows, define roles, and manage releases.\
Then embed escrow status widgets or Viewer links on your own landing pages.

→ *Best for pilots, MVPs, or early marketplaces.*

***

**2. Hybrid API + Back Office**

Create escrows through the API (from your app),\
but handle approvals or disputes in the Back Office.\
Combine your UX with our governance layer.

→ *Best for platforms that want control, without managing every on-chain flow.*

***

**3. Transparency Add-On**

Keep your existing payment flow,\
but connect your users to the Escrow Viewer for proof-of-funds and progress tracking.

→ *Best for compliance-heavy or high-trust environments.*

***

**4. Template Fork**

Fork the Demo dApp or Back Office,\
rebrand it, integrate your wallet provider or custom logic, and ship fast.

→ *Best for startups or teams that want to own the UI but use our underlying logic.*

***

#### 🌍 Example Hybrid Flow

**Scenario:** A freelance marketplace wants to add milestone-based payments.

* They deploy escrows in the **Back Office**.
* Use their own **frontend** (built in Next.js) to list jobs and show milestone progress.
* Embed the **Escrow Viewer** link for each job to give users transparent proof-of-funds.
* When ready to scale, they integrate the **API** to automate escrow creation and releases.

No blockchain devs. No audits. Just composable infrastructure.

***

#### 🧠 Why This Architecture Wins

* **Decentralization = Independence**\
  You’re not locked into a vendor or a custodial middleman.\
  The contract exists on-chain, and your users can verify it anytime.
* **Hybrid = Speed**\
  You can start no-code and move to code later.\
  Back Office today, API tomorrow — same logic, same escrows.
* **Transparency = Trust**\
  The Viewer turns every transaction into a live proof-of-funds page.\
  Users don’t have to take your word — they can see the escrow themselves.

***

#### 💡 Key Takeaway

Trustless Work isn’t just an escrow API — it’s an **architecture for programmable trust.**\
You can centralize your UX while decentralizing your money flow.\
You can use our Back Office as your admin layer, the Viewer as your transparency layer,\
and the API as your automation layer — all connected to the same on-chain contracts.

> **You own the experience.**\
> **The blockchain owns the trust.**


# Escrow products Mix & Match Guide

From idea to escrow in one day.

Designing an escrow is only half the battle. The real question is:\
**How do you go from schema to a working product without burning months on contracts, audits, and ops flows?**

That’s why Trustless Work offers a **modular product suite** — tools you can combine like building blocks to launch escrow-powered workflows today.

***

### The Product Suite

* **Escrow API** – The programmable core. Create, fund, update, approve, and release escrows. Maximum control, minimal friction.
* **Next.js SDK** – React-friendly wrapper for interacting with escrows directly from your frontend.
* **Escrow Blocks** – Pre-built React UI components. The fastest way to launch a user-facing escrow flow.
* **Back Office dApp (Open Source)** – Ops-friendly control panel for deploying and managing escrows. Ideal for dispute resolution, MVP pilots, and non-technical teams. Use it, clone it.
* **Demo Lab dApp** – Developer sandbox to test flows before pushing to production.
* **Escrow Viewer (Open Source)** – Public, read-only explorer of escrow configs, milestones, and balances. Essential for transparency and compliance.

***

### Integration Models

Think of these as **playbooks** for how to mix & match the suite:

1. **Full API/SDK Integration**\
   → For teams with dev capacity and UX control needs.\
   Your UI + our escrow logic.
2. **Escrow Blocks:** \
   → Import template UI components to launch faster, with minimal custom frontend work.
3. **Hybrid Back Office**\
   → Your users stay in your UI, but ops/disputes handled in the Back Office.
4. **Back Office First**\
   → Launch this week. Manage flows directly in our Back Office while validating.
5. **Template Fork**\
   → Clone one of our open-source dApps, rebrand, extend. Perfect for hackathons.


# Stellar Network

Escrows need rails. Trustless Work runs on Stellar, a blockchain optimized for stablecoins, payments, and smart contracts.

Trustless Work contracts run on **Stellar**. Smart contract logic runs on **Soroban**.

Wallets sign the transactions. Trustlines define which assets accounts can hold.

{% hint style="info" %}
**Why it matters:** Stellar gives fast finality and low fees. Soroban makes the escrow logic programmable.
{% endhint %}

### Why Stellar?

* **Fast finality.** Most transactions confirm in \~5 seconds.
* **Low fees.** Transaction fees are typically fractions of a cent.
* **Built for payments.** Wallets, exchanges, and on/off-ramps already support Stellar.
* **Stablecoin-ready.** USDC is widely used on Stellar, plus any issued asset.

### Why Soroban?

Soroban is Stellar’s smart contract engine.

It powers **programmable escrows**. You can encode roles, milestones, approvals, disputes, and release logic on-chain.

### Start here

<table data-view="cards"><thead><tr><th>Topic</th><th data-card-target data-type="content-ref">Link</th></tr></thead><tbody><tr><td>Trustlines</td><td><a href="/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/nEiYOyWRTKGdGK2Vj8Ne">/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/nEiYOyWRTKGdGK2Vj8Ne</a></td></tr><tr><td>Testnet Tokens</td><td><a href="/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/sAtUC3JiknZlM5Ft90fq">/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/sAtUC3JiknZlM5Ft90fq</a></td></tr><tr><td>Stellar Wallets</td><td><a href="/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/hnolwfVIvAzhFQthX4sB">/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/hnolwfVIvAzhFQthX4sB</a></td></tr></tbody></table>

<details>

<summary>Coming soon</summary>

* Issued assets on Stellar (USDC and other tokens)
* Libraries & tooling (Soroban + wallet integration helpers)

</details>

{% hint style="success" %}
If you’re building locally, start with **Testnet Tokens** and **Trustlines** first.
{% endhint %}


# Trustlines

On Stellar, accounts must explicitly opt in to hold and use assets. This opt-in is called a trustline.

Trustlines are how Stellar accounts opt in to **issued assets**.

If an account has no trustline, it cannot hold that asset.

{% hint style="info" %}
Each trustline increases the account’s minimum balance by **0.5 XLM** (base reserve).
{% endhint %}

### What is a trustline?

* A trustline links an account to an **asset issuer**.
* It allows the account to **receive, hold, and send** that asset.
* It includes a **limit** (max balance you accept).
* It tracks balance and liabilities (like open offers).

### Why trustlines matter for escrows

Trustless Work escrows can use **any Stellar-issued asset**.

Every participant must be able to hold that asset.

{% hint style="warning" %}
If a signer can’t hold the escrow asset, their step may fail. Set trustlines before testing any escrow flow.
{% endhint %}

### Issuer addresses (USDC / EURC)

Use these issuer addresses when you configure the escrow trustline.

{% tabs %}
{% tab title="USDC" %}
**Testnet issuer**

[`GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5`](https://stellar.expert/explorer/testnet/asset/USDC-GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5)

**Mainnet issuer**

[`GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN`](https://stellar.expert/explorer/public/asset/USDC-GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN)
{% endtab %}

{% tab title="EURC" %}
**Testnet issuer**

[`GB3Q6QDZYTHWT7E5PVS3W7FUT5GVAFC5KSZFFLPU25GO7VTC3NM2ZTVO`](https://stellar.expert/explorer/testnet/asset/EURC-GB3Q6QDZYTHWT7E5PVS3W7FUT5GVAFC5KSZFFLPU25GO7VTC3NM2ZTVO?asset%5B%5D=EURC-GB3Q6QDZYTHWT7E5PVS3W7FUT5GVAFC5KSZFFLPU25GO7VTC3NM2ZTVO-1)

**Mainnet issuer**

[`GDHU6WRG4IEQXM5NZ4BMPKOXHW76MZM4Y2IEMFDVXBSDP6SJY4ITNPP2`](https://stellar.expert/explorer/public/asset/EURC-GDHU6WRG4IEQXM5NZ4BMPKOXHW76MZM4Y2IEMFDVXBSDP6SJY4ITNPP2)
{% endtab %}
{% endtabs %}

{% hint style="info" %}
**References**

* Circle: [USDC contract addresses](https://developers.circle.com/stablecoins/usdc-contract-addresses)
* Circle: [EURC contract addresses](https://developers.circle.com/stablecoins/eurc-contract-addresses)
* Community: [Stellar stablecoin explorer](https://stablecoin.stellarlight.xyz/)
  {% endhint %}


# Testnet Tokens

## **What Are Testnet Tokens?**

Testnet tokens are virtual assets used on Stellar's test network (testnet) to:

* Test wallet setups.
* Experiment with sending and receiving payments.
* Learn Stellar operations like creating trustlines or setting up smart contracts.

### **Why Use Testnet Tokens?**

* **Risk-Free Learning:** No monetary value; perfect for practice.
* **Development Testing:** Test your applications or smart contracts before deploying on the mainnet.
* **Community Access:** Many developers and testers rely on the testnet for Stellar experiments.

***

## **How to Obtain XLM Testnet Tokens**

### **Option 1: Use the Stellar Lab Faucet**

1. Go to the **Stellar Laboratory**:\
   [Stellar Laboratory](https://lab.stellar.org/account/fund?$=network$id=testnet\&label=Testnet\&horizonUrl=https:////horizon-testnet.stellar.org\&rpcUrl=https:////soroban-testnet.stellar.org\&passphrase=Test%20SDF%20Network%20/;%20September%202015;;)
2. Paste your **Public Key** into the faucet's input field.
3. Click **"Request Lumens"**:
   * You’ll receive a transaction confirmation.
   * Check your wallet to confirm receipt of 10,000 XLM test tokens.

***

### **Option 2: Use Stellar Command-Line Interface (CLI)**

1. Install the Stellar CLI:
   * Install the `stellar-core` or `stellar-horizon` command-line tool (refer to Stellar documentation).
2. Request Tokens:
   * Run the following command:

     ```bash
     stellar-cli request-tokens --network testnet --public-key <Your Public Key>
     ```
   * Replace `<Your Public Key>` with your Stellar wallet address.
3. Verify Balance:
   * Use the CLI or a Stellar wallet to check your testnet account balance.

***

### **How to Get Testnet USDC**

1. **Set the Trustline:** Ensure you've established a trustline for USDC on your Stellar testnet account. \
   Issuer: GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5
2. **Visit the Circle USDC Faucet:**
   * Go to [Circle USDC Faucet](https://faucet.circle.com/).
3. **Select Stellar and Request USDC:**
   * Use the dropdown menu to select "Stellar".
   * Paste your Stellar testnet address.
   * Click on "Get Tokens" to receive testnet USDC.

***

## **How to Use Testnet Tokens**

### **1. Explore Wallet Operations**

* Send tokens between test accounts.
* Experiment with memo fields, transaction fees, and multi-signature setups.

### **2. Learn Key Stellar Concepts**

* **Trustlines:** Use testnet tokens to create trustlines for custom assets.
* **Asset Issuance:** Test issuing and trading custom assets.
* **Smart Contracts:** Experiment with Stellar's **pre-signed transactions** to simulate smart contracts.

### **3. Connect to Applications**

* Use your testnet wallet with Stellar-based dApps like **Trustless Work** to test integrations.

***

***

## **Important Notes**

1. **Testnet Tokens Have No Value:**
   * These tokens are strictly for testing and cannot be transferred to the mainnet.
2. **Testnet Environment Resets:**
   * The Stellar testnet resets periodically, clearing all test accounts and balances.
   * Always re-create your accounts and re-fund them when the testnet resets.
3. **Avoid Sharing Secret Keys:**
   * Even in a test environment, keep your **Secret Key** secure to mimic best practices for the mainnet.

***

## **Troubleshooting & FAQs**

### **I didn’t receive test tokens. What should I do?**

* Ensure you’ve used the correct **Public Key**.
* Try another method (e.g., Stellar Faucet vs. Laboratory).
* Wait for a few minutes as the testnet might experience delays.

### **Why can’t I switch my wallet to Testnet?**

* Make sure your wallet supports Stellar’s testnet.
* Check for updates or consider using a wallet that supports testnet, like Freighter or Rabet.

### **What happens if I lose my Secret Key?**

* Without the Secret Key, you cannot access your testnet account. Treat it as you would a real wallet key.

***

## **Additional Resources**

* [Stellar Testnet Status](https://status.stellar.org/)
* [Stellar Laboratory](https://laboratory.stellar.org/)
* [Stellar Developer Documentation](https://developers.stellar.org/)
* [Stellar Discord Community](https://discord.com/invite/stellar)

***

By following this guide, you can confidently explore Stellar’s testnet and test a variety of operations risk-free.


# Stellar Wallets

A Comprehensive Developer's Guide to Stellar Wallet Integrations

## Introduction to Stellar Wallets

Stellar wallets are essential tools for interacting with the Stellar blockchain, enabling developers and users to securely manage, send, and receive digital assets. This section covers the setup and integration of popular Stellar wallets:

* [**Freighter Wallet**](/trustless-work/introduction/stellar-and-soroban-the-backbone-of-trustless-work/stellar-wallets/freighter-wallet)
* **Albedo Wallet**
* **xBull Wallet**
* **Rabet Wallet**
* **Lobstr Wallet**
* **Hana Wallet**

## Key Concepts

### Public and Private Keys

* **Public Key:** Your `Stellar address`, used to receive assets. This can be shared publicly.
* **Private Key:** Your secret key used to authorize transactions. This must be kept secure and never shared.
* **Never share your private key with anyone**

## Trustlines

Stellar accounts need to establish trustlines to receive custom assets. Trustlines represent a relationship between two accounts, where one account trusts the other to issue a specific asset. This allows the receiving account to accept and hold that asset.

Trustlines are crucial in Stellar for:

* Establishing trust with asset issuers
* Enabling receipt of custom tokens
* Requiring a small minimum balance to create

## Minimum Balance Requirements

* Stellar accounts require a minimum balance (currently 0.5 XLM)
* Each trustline adds to the minimum balance requirement
* Helps prevent spam and ensures network stability

## Security Best Practices

* Use hardware wallets when possible
* Enable two-factor authentication
* Store private keys offline
* Use secure, updated browsers
* Regularly update wallet software
* Be cautious of phishing sites


# Freighter Wallet

![Rabet Wallet Logo](/files/YA9odovM35IieNiaNQRd)

Freighter is a **browser extension wallet** for Stellar. It is a non-custodial wallet extension for your browser.

***

## **What You’ll Learn**

* How to install and set up Freighter Wallet.
* How to connect Freighter Wallet to Trustless Work.
* Useful resources, security tips, and FAQs.

***

## **Installation**

### **Step-by-Step Instructions:**

1. Open the official [Freighter Wallet website](https://www.freighter.app/).
2. Click on **"Add to Browser"** for your preferred browser (e.g., Chrome, Brave, or Firefox).
   * Ensure you download only from the official website to avoid scams.
3. Follow the browser prompts to install the extension.
4. After installation, pin the Freighter extension for easy access.

![Freighter Preview](/files/i7XqLhZoIqUnvIYyFgHO)

***

## **Setting Up Freighter Wallet**

### **Creating a New Wallet**

1. Open the Freighter extension by clicking on its icon in your browser.
2. Click on **"Create New Wallet"**.
3. Set a secure password (store this password securely).
4. Freighter will generate a **Recovery Phrase** (also called a Seed Phrase).
   * Write it down and store it in a safe place. **Do not share it with anyone**.

![Freighter Setup](/files/AkubGfwWBm1MPMu71T6V) ![Freighter Setup](/files/i16xfCgnBbdHwfZbrp4y)

### Fund your Testnet account

You need a funded Testnet account to submit transactions and pay fees.

1. Open the Freighter extension.
2. Switch the network to **Testnet**.

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

3. Click **Fund with Friendbot**.

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

4. Wait for the balance to appear.
5. Your account is now active on Stellar Testnet.

{% hint style="info" %}
Friendbot only works on **Testnet**. If you don’t see the button, verify the network first.
{% endhint %}

<details>

<summary>Friendbot fallback (manual)</summary>

If the in-wallet Friendbot flow fails, you can request funds directly:

1. Copy your account address (your public key) from Freighter.
2. Open: `https://friendbot.stellar.org/?addr=YOUR_PUBLIC_KEY`
3. Replace `YOUR_PUBLIC_KEY` with your address and load the URL.

</details>

### **Importing an Existing Wallet**

1. Open the Freighter extension.
2. Click on **"Import Wallet"**.
3. Enter your existing Seed Phrase and set a password.

![Freighter Setup](/files/AkubGfwWBm1MPMu71T6V)

***

## **Connecting Freighter to Trustless Work**

1. Navigate to the Trustless Work platform.
   * Example link: [Trustless Work](https://dapp.trustlesswork.com/).
2. Click **"Connect Wallet"** in the top-right corner of the page.
3. Select **"Freighter Wallet"** from the list of options.
4. A pop-up will appear from Freighter asking for confirmation.
5. Approve the connection in the wallet extension.

![Trustless Work](/files/IPqMt7z9bD1BFLRBSOB1) ![Wallet](/files/F36E6sUalRGIdGvIr0sl)

### **Note:**

* Ensure Freighter is set to the correct network (Testnet or Mainnet) based on your environment. You can toggle the network in the Freighter settings.

***

## **Best Practices and Security Tips**

* **Backup Your Seed Phrase:** Store it in a secure, offline location.
* **Use Testnet for Development:** When testing or experimenting, always switch to the Testnet to avoid losing real funds.
* **Enable Browser Security Features:** Avoid installing unknown browser extensions that could compromise your wallet.

***

## **Useful Links and Resources**

* **Official Website:** [Freighter Wallet](https://www.freighter.app/)
* **Documentation:** [Freighter GitHub Repo](https://github.com/stellar/freighter)
* **Testnet Tokens:** [How to Get Testnet Tokens](/trustless-work/introduction/stellar-and-soroban-the-backbone-of-trustless-work/testnet-tokens)
* **Troubleshooting:** [Troubleshooting & FAQs](/trustless-work/support/troubleshooting)

***

## **Frequently Asked Questions**

### **Q: What happens if I lose my recovery phrase?**

* Your recovery phrase is the only way to restore your wallet. If it’s lost, your funds cannot be recovered.

### **Q: How do I switch between Testnet and Mainnet?**

1. Open the Freighter extension.
2. Click on the settings icon.
3. Toggle between Testnet and Mainnet in the dropdown.


# Developer Guide

Start building on Trustless Work with the REST API or SDKs.

Trustless Work is **Escrow-as-a-Service** on **Stellar (Soroban)**.

Use it to deploy escrows, fund them, track milestones, and release funds. Your app drives the flow via **REST API** or **SDKs**.

{% hint style="info" %}
Most write endpoints return an **unsigned XDR**.\
You must sign it client-side with the correct **role wallet**.
{% endhint %}

### Pick your integration path

#### REST API

Use this if you want full control and you’re already signing Stellar transactions.

* [REST API: Introduction](/trustless-work/api-rest/introduction)

#### React SDK (hooks)

Use this if you want typed hooks for every escrow action.

* [React SDK: Getting Started](/trustless-work/escrow-react-sdk/getting-started)

#### Escrow Blocks SDK (UI blocks)

Use this if you want ready-made UI blocks and wallet connectivity.

* [Escrow Blocks SDK: Getting Started](/trustless-work/escrow-blocks-sdk/getting-started)

### Quickstart (recommended order)

{% stepper %}
{% step %}

### 1) Get access

Request an API key. You’ll need it for deploy/fund/release/dispute flows.

* [Request API Key](/trustless-work/introduction/developer-resources/request-api-key)
  {% endstep %}

{% step %}

### 2) Set up auth + signing

Wire up the auth header. Then get your wallet(s) ready to sign XDR.

* [Authentication](/trustless-work/introduction/developer-resources/authentication)
  {% endstep %}

{% step %}

### 3) Learn the data model

You’ll use these types in every request/response.

* [Schema](/trustless-work/introduction/developer-resources/schema)
* [Types](/trustless-work/introduction/developer-resources/types)
  {% endstep %}

{% step %}

### 4) Implement the core flow

Typical sequence:

1. Deploy / initialize escrow
2. Fund escrow
3. Approve or update milestones (if used)
4. Release funds (or dispute + resolve)

Use the checklist to cover edge cases and role permissions.

* [Integration checklist](/trustless-work/introduction/developer-resources/integration-checklist)
  {% endstep %}
  {% endstepper %}

### Prereqs (Stellar)

* [Stellar Wallets](/trustless-work/introduction/stellar-and-soroban-the-backbone-of-trustless-work/stellar-wallets)
* [Trustlines](/trustless-work/introduction/stellar-and-soroban-the-backbone-of-trustless-work/trustlines)
* [Testnet Tokens](/trustless-work/introduction/stellar-and-soroban-the-backbone-of-trustless-work/testnet-tokens)

### Concepts and architecture

* [Escrow Design](/trustless-work/introduction/technology-overview)
* [Architecture](/trustless-work/introduction/developer-resources/architecture)
* [Escrow products Mix & Match Guide](/trustless-work/introduction/technology-overview/smart-escrow-design)

### Try the Backoffice dApp

Use it to request API keys and test flows end-to-end.

{% embed url="<https://dapp.trustlesswork.com>" %}


# Request API Key

Request an API Key to interact with all the endpoints.

To interact with the Trustless Work API, you’ll need to generate an API Key.\
This key authenticates your requests and links them to your verified wallet identity.\
\
**Overview:**\
API keys are managed directly in the **Trustless Work BackOffice dApp**.\
They are required **only** if you plan to interact **programmatically** with the API —\
you don’t need one for using the dApp interface itself.

{% embed url="<https://dapp.trustlesswork.com>" %}

***

#### Step 1 — Connect Your Stellar Wallet

To begin, connect a **Stellar-compatible wallet** (such as **Freighter**, **Albedo**, or **xBull**) to the dApp.\
You’ll be prompted to **sign a message** — this confirms ownership of your wallet and automatically creates your **user profile**.

If you’ve never used a Stellar wallet before, check out the Stellar Wallets section for setup instructions.

{% content-ref url="/pages/hnolwfVIvAzhFQthX4sB" %}
[Stellar Wallets](/trustless-work/introduction/stellar-and-soroban-the-backbone-of-trustless-work/stellar-wallets)
{% endcontent-ref %}

***

#### Step 2 — Complete Your Profile

Once logged in:

1. Click your **wallet address** at the bottom-left corner.
2. Select **Settings** from the menu.
3. Fill out your profile with basic details — **name, email, and use case**.
   * The **Use Case** field is required before you can generate an API key.
   * This helps us understand your integration goals and provide better support.

> 💡 Tip: You can always update your profile later to reflect new projects or integrations.

***

#### Step 3 — Request an API Key

In the **Settings sidebar**, navigate to the **API Keys** tab:

1. **Choose a Network:**
   * `Testnet` — For development and testing
   * `Mainnet` — For production (available post-audit)
2. Click **Request API Key** to generate a new key.
3. **Copy it immediately** — once you close the dialog, it **cannot be viewed again** for security reasons.\
   You’ll need to generate a new one if lost.

> ⚠️ You must confirm that you’ve copied the key before exiting the dialog.

{% hint style="warning" %}
You must have at least the **use case** filled, if not, the system won't give you the API Key.
{% endhint %}

***

#### 🧠 Summary

| Action           | Description                                      |
| ---------------- | ------------------------------------------------ |
| Connect Wallet   | Log in and sign to create your profile.          |
| Complete Profile | Fill in personal info and use case (required).   |
| Request Key      | Generate a key from the API Keys tab.            |
| Save Securely    | Copy and store it safely — it’s shown only once. |

***

#### ✅ Ready to Build

Once you have your API key, you can start interacting with the Trustless Work API to:

* Deploy and fund escrows
* Mark milestones as complete
* Approve, dispute, or release payments
* Query escrow status and balances

Explore the [API Reference](broken://pages/ZzuxcJ2Y0YqqSIjhhxFP) section to see available endpoints.


# Integration checklist

**Goal:** Go from idea to live escrows in **under 1 week**.

**Time Estimate:** 4–8 hours of implementation (plus testing).

**Prerequisites:**

* Basic Web3 knowledge
* A Stellar wallet (Freighter, Albedo)
* Access to stablecoins (USDC/EURC on testnet or mainnet)

***

### **Phase 1 – Preparation (Setup & Planning)**

**1. Understand Your Use Case**

* [ ] Define your escrow workflow: single-release (full payout at end) or multi-release (payout per milestone).
* [ ] Map your transaction lifecycle: Initiation → Funding → Milestone Updates → Approval → Release (→ Dispute if needed).

📄 [Escrow Lifecycle](/trustless-work/introduction/technology-overview/escrow-lifecycle)

**2. Choose the Correct Escrow Type**

* [ ] 📄 [Escrow Types](/trustless-work/introduction/technology-overview/escrow-types)
* [ ] **Single-Release** — full payout after all milestones approved.
* [ ] **Multi-Release** — staged payouts per milestone.

**3. Define Roles**

Assign the parties' Stellar addresses to each role in your escrow:📄 [Roles in Trustless Work](/trustless-work/introduction/technology-overview/roles-in-trustless-work)

* [ ] **Approver** — approves or disputes milestones.
* [ ] **Service Provider** — delivers work, marks milestones complete.
* [ ] **Release Signer** — releases funds once approvals are complete.
* [ ] **Dispute Resolver** — resolves disputes.
* [ ] **Platform Address** — receives platform fees.
* [ ] **Receiver** — final recipient of funds.

**4. Define Escrow Properties**

[Escrow Properties](/trustless-work/introduction/technology-overview/what-does-a-smart-escrow-look-like)

* [ ] Asset & trustline setup
* [ ] Amount & platform fee
* [ ] Engagement ID (invoice/order ref)
* [ ] Milestones (title, description, acceptance criteria)

***

### **Phase 2 – Integration (Core Setup)**

**5. Get Access**

* [ ] Sign up at [dApp](https://dapp.trustlesswork.com).
* [ ] Request **API Key** (testnet; mainnet post-audit) [Request API Key](/trustless-work/introduction/developer-resources/request-api-key) -> you can see the videos on the dApp landing.
* [ ] You can deploy testney & Mainnet escrows on the backoffice. Great for testing and integrating.&#x20;

**6. Install SDK / Tools** [Getting Started](/trustless-work/escrow-react-sdk/getting-started)

* [ ] Install NPM package.
* [ ] Import SDK into your project.
* [ ] Clone or reference open-source templates for your vertical (e.g., P2P, marketplace, grant platform).
* [ ] OR: Use escrow blocks&#x20;

**7. Configure Your Escrow**

* [ ] Set roles, addresses, amount, fees, and milestones.
* [ ] Choose single-release or multi-release logic.
* [ ] Use testnet asset for initial integration.

***

### **Phase 3 – Testing (Validation & Debugging)**

**8. Deploy on Testnet**

* [ ] Create your first escrow via API or SDK.
* [ ] Fund it using a testnet wallet (e.g., Freighter, Albedo).
* [ ] Walk through milestone completion and approval flow.

**9. Simulate Edge Cases**

* [ ] Dispute handling
* [ ] Partial funding
* [ ] Timeout or cancellation flows

**10. Run Compliance & UX Review**

* [ ] KYC/AML readiness (if needed for your vertical).
* [ ] Test wallet connection & signing UX.

***

### **Phase 4 – Launch (Go Live)**

**11. Migrate to Mainnet**

* [ ] Move Trustless Work to Mainnet
* [ ] Deploy Mainnet contracts using SDK or API.
* [ ] Fund first live escrows with stablecoins.

**12. Monitor & Optimize**

* [ ] Use viewer or dApp backoffice to track escrow status, funding, and release.

***

***


# Authentication

In order to get registered,  you have to connect with a Stellar wallet. If you do not yet have one, or have never used one, there is more information in the following section:&#x20;

{% content-ref url="/pages/hnolwfVIvAzhFQthX4sB" %}
[Stellar Wallets](/trustless-work/introduction/stellar-and-soroban-the-backbone-of-trustless-work/stellar-wallets)
{% endcontent-ref %}

To authenticate you will need to login to our Dapp with a Stellar Wallet and Request an API key. Here are the steps to achieve that:&#x20;

{% content-ref url="/pages/rk6FfPZG0cVD1uYYThg4" %}
[Request API Key](/trustless-work/introduction/developer-resources/request-api-key)
{% endcontent-ref %}

\
**Coming:** \
We are figuring out how this can work with passkeys and send to addresses with Memo. \
WE do this in the open, so feel free to crontribute. [Broken mention](broken://pages/BDEDz7igAgRHxtqzbZwM)


# Schema

In this section you will be able to see the outline of the types of escrow's that Trustless Work offers. With these diagrams you will be able to know the structure and properties of an escrow both in its Single-Release and Multi-Release versions.

## Single Release Escrow Schema

#### Escrow body:

| Key          | Type              | Description                                                                   |
| ------------ | ----------------- | ----------------------------------------------------------------------------- |
| engagementId | string            | Unique identifier for the escrow                                              |
| title        | string            | Name of the escrow                                                            |
| roles        | Roles Object      | Roles that make up the escrow structure                                       |
| description  | string            | Text describing the function of the escrow                                    |
| amount       | number            | Amount to be transferred upon completion of escrow milestones                 |
| plataformFee | number            | Commission that the platform will receive when the escrow is completed        |
| milestones   | Milestone\<Array> | Objectives to be completed to define the escrow as completed                  |
| flags        | Flags Object      | Flags validating certain escrow life states                                   |
| trustline    | Trustline Object  | Information on the trustline that will manage the movement of funds in escrow |

#### Roles:

| Name             | Type   | Description                                                                          |
| ---------------- | ------ | ------------------------------------------------------------------------------------ |
| approver         | string | Address of the entity requiring the service.                                         |
| serviceProvider  | string | Address of the entity providing the service.                                         |
| plataformAddress | string | Address of the entity that owns the escrow                                           |
| releaseSigner    | string | Address of the user in charge of releasing the escrow funds to the service provider. |
| disputeResolver  | string | Address in charge of resolving disputes within the escrow.                           |
| receiver         | string | Address where escrow proceeds will be sent to                                        |

#### Milestone:

| Name        | Type              | Description                                                            |
| ----------- | ----------------- | ---------------------------------------------------------------------- |
| description | string            | Text describing the function of the milestone.                         |
| status      | string            | Milestone status. Ex: Approved, In dispute, etc...                     |
| evidence    | string (optional) | Evidence of work performed by the service provider.                    |
| approved    | boolean           | Flag indicating whether a milestone has been approved by the approver. |

#### Flags:

| Name     | Type    | Description                                                       |
| -------- | ------- | ----------------------------------------------------------------- |
| disputed | boolean | Flag indicating that an escrow is in dispute.                     |
| released | boolean | Flag indicating that escrow funds have already been released.     |
| resolved | boolean | Flag indicating that a disputed escrow has already been resolved. |

#### Trustline:

| Name    | Type   | Description                                                                            |
| ------- | ------ | -------------------------------------------------------------------------------------- |
| address | string | Public address establishing permission to accept and use a specific token.             |
| symbol  | string | Official abbreviation representing the token in wallets, exchanges, and documentation. |

### Single Release Escrow Flow:

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

## Multi Release Escrow Schema

| Key          | Type              | Description                                                                   |
| ------------ | ----------------- | ----------------------------------------------------------------------------- |
| engagementId | string            | Unique identifier for the escrow                                              |
| title        | string            | Name of the escrow                                                            |
| description  | string            | Text describing the function of the escrow                                    |
| roles        | Roles Object      | Roles that make up the escrow structure                                       |
| plataformFee | number            | Commission that the platform will receive when the escrow is completed        |
| milestones   | Milestone\<Array> | Objectives to be completed to define the escrow as completed                  |
| trustline    | Trustline Object  | Information on the trustline that will manage the movement of funds in escrow |

#### Roles:

| Name             | Type   | Description                                                                          |
| ---------------- | ------ | ------------------------------------------------------------------------------------ |
| approver         | string | Address of the entity requiring the service.                                         |
| serviceProvider  | string | Address of the entity providing the service.                                         |
| plataformAddress | string | Address of the entity that owns the escrow                                           |
| releaseSigner    | string | Address of the user in charge of releasing the escrow funds to the service provider. |
| disputeResolver  | string | Address in charge of resolving disputes within the escrow.                           |

#### Milestone:

| Name        | Type              | Description                                                    |
| ----------- | ----------------- | -------------------------------------------------------------- |
| description | string            | Text describing the function of the milestone.                 |
| status      | string            | Milestone status. Ex: Approved, In dispute, etc...             |
| flags       | Flags Object      | Flags validating certain escrow life states.                   |
| evidence    | string (optional) | Evidence of work performed by the service provider.            |
| amount      | number            | Amount to be transferred upon completion of escrow milestones. |
| receiver    | string            | Address where escrow proceeds will be sent to                  |

#### Flags:

| Name     | Type    | Description                                                            |
| -------- | ------- | ---------------------------------------------------------------------- |
| disputed | boolean | Flag indicating that an escrow is in dispute.                          |
| released | boolean | Flag indicating that escrow funds have already been released.          |
| resolved | boolean | Flag indicating that a disputed escrow has already been resolved.      |
| approved | boolean | Flag indicating whether a milestone has been approved by the approver. |

#### Trustline:

| Name    | Type   | Description                                                                            |
| ------- | ------ | -------------------------------------------------------------------------------------- |
| address | string | Public address establishing permission to accept and use a specific token.             |
| symbol  | string | Official abbreviation representing the token in wallets, exchanges, and documentation. |

### Multi Release Escrow Flow:

<figure><img src="/files/3jT5PCg8hfwaT3qCB9Q3" alt=""><figcaption></figcaption></figure>


# Architecture

Step-by-step instructions to help you connect your product with Trustless Work smoothly and efficiently.

## Overview

The purpose of this document is to provide a comprehensive guide on implementing best practices within the development team. It covers essential methodologies, tools, and strategies that can enhance productivity and ensure high-quality outcomes.

### Basic Flow

Most common flow in the dApps.

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

***

### Services - Endpoints

Flow that must always be executed at each Endpoint **except** `Get Balances & Get Escrow`

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

The document describes the essential execution flow for service endpoints, with exceptions for `Get Balances` and `Get Escrow`, ensuring uniformity in implementation.


# Types

All the entities that you'll need.

## Overview

In this document, we explore the structure and functionality of key escrow-related types and interfaces used in the system, including the Escrow and Escrow Response entities. These entities are crucial for handling escrow operations such as initializing, updating, and responding to requests regarding escrow contracts.

Our React library includes all these types. Simply import them.


# Basic

### Status, baseURL and HttpMethos

```typescript
/**
 * The base URL for the Trustless Work API
 */
export type baseURL =
  | "https://api.trustlesswork.com"
  | "https://dev.api.trustlesswork.com";

/**
 * Escrow Type
 */
export type EscrowType = "single-release" | "multi-release";

/**
 * Http Method
 */
export type HttpMethod = "get" | "post" | "put" | "delete";

/**
 * Unique possible statuses for a Trustless Work request
 */
export type Status = "SUCCESS" | "FAILED";

/**
 * Date
 */
export type Date = {
  _seconds: number;
  _nanoseconds: number;
};

```


# Entities

### Escrow

Contains both single-release and multiple-release types.

```typescript
/**
 * Single Release Escrow
 */
export type SingleReleaseEscrow = {
  /**
   * Address of the user signing the contract transaction
   */
  signer: string;

  /**
   * ID (address) that identifies the escrow contract
   */
  contractId: string;

  /**
   * Unique identifier for the escrow
   */
  engagementId: string;

  /**
   * Name of the escrow
   */
  title: string;

  /**
   * Roles that make up the escrow structure
   */
  roles: Roles;

  /**
   * Text describing the function of the escrow
   */
  description: string;

  /**
   * Amount to be transferred upon completion of escrow milestones
   */
  amount: number;

  /**
   * Commission that the platform will receive when the escrow is completed
   */
  platformFee: number;

  /**
   * Amount of the token (XLM, USDC, EURC, etc) in the smart contract.
   */
  balance: number;

  /**
   * Objectives to be completed to define the escrow as completed
   */
  milestones: SingleReleaseMilestone[];

  /**
   * Flags validating certain escrow life states
   */
  flags?: Flags;

  /**
   * Information on the trustline that will manage the movement of funds in escrow
   */
  trustline: Trustline;
};

/**
 * Multi Release Escrow
 */
export type MultiReleaseEscrow = Omit<
  SingleReleaseEscrow,
  "milestones" | "flags" | "amount" | "roles"
> & {
  milestones: MultiReleaseMilestone[];
  roles: Omit<Roles, "receiver">;
};
```

### Milestone

Contains both single-release and multiple-release types. Both of them based on the BaseMilestone.

```typescript
/**
 * Milestone
 */
type BaseMilestone = {
  /**
   * Text describing the function of the milestone.
   */
  description: string;

  /**
   * Milestone status. Ex: Approved, In dispute, etc...
   */
  status?: string;

  /**
   * Evidence of work performed by the service provider.
   */
  evidence?: string;
};

/**
 * Single Release Milestone
 */
export type SingleReleaseMilestone = BaseMilestone & {
  /**
   * Approved flag, only if the escrow is single-release
   */
  approved?: boolean;
};

/**
 * Multi Release Milestone
 */
export type MultiReleaseMilestone = BaseMilestone & {
  /**
   * Amount to be transferred upon completion of this milestone
   */
  amount: number;
  
  /**
   * Address where milestone proceeds will be sent to
   */
  receiver: string;

  /**
   * Flags validating certain milestone life states, only if the escrow is multi-release
   */
  flags?: Flags;
};
```

### Trustline

```typescript
/**
 * Trustline
 */
export type Trustline = {
  /**
   * Symbol of the token, example: USDC, EURC, etc...
   */
  symbol: string;

  /**
   * Public address establishing permission to accept and use a specific token.
   */
  address: string;
};
```

### Flags

All the possible flags **only in multi-release escrow.**

```typescript
/**
 * Flags
 */
export type Flags = {
  /**
   * Flag indicating that an escrow is in dispute.
   */
  disputed?: boolean;

  /**
   * Flag indicating that escrow funds have already been released.
   */
  released?: boolean;

  /**
   * Flag indicating that a disputed escrow has already been resolved.
   */
  resolved?: boolean;

  /**
   * Flag indicating whether a milestone has been approved by the approver.
   */
  approved?: boolean;
};

```

### Roles

```typescript
/**
 * Roles
 */
export type Roles = {
  /**
   * Address of the entity requiring the service.
   */
  approver: string;

  /**
   * Address of the entity providing the service.
   */
  serviceProvider: string;

  /**
   * Address of the entity that owns the escrow
   */
  platformAddress: string;

  /**
   * Address of the user in charge of releasing the escrow funds to the service provider.
   */
  releaseSigner: string;

  /**
   * Address in charge of resolving disputes within the escrow.
   */
  disputeResolver: string;

  /**
   * Address where escrow proceeds will be sent to (In the “Multi-Release” version, 
     this role is at the milestone level.)
   */
  receiver: string;
};

/**
 * Role
 */
export type Role =
  | "approver"
  | "serviceProvider"
  | "platformAddress"
  | "releaseSigner"
  | "disputeResolver"
  | "receiver"
  | "signer";
```


# Payloads

### Escrow's Payload Entity

```typescript
import { EscrowType, SingleReleaseEscrowStatus } from "./types";
import { MultiReleaseEscrow, Role, SingleReleaseEscrow } from "./types.entity";

/**
 * Documentation: https://docs.trustlesswork.com/trustless-work/developer-resources/quickstart/integration-demo-project/entities
 */

// ----------------- Milestone Payloads -----------------
/**
 * Single Release Milestone Payload
 */
export type SingleReleaseMilestonePayload = {
  /**
   * Text describing the function of the milestone
   */
  description: string;
};

/**
 * Multi Release Milestone Payload
 */
export type MultiReleaseMilestonePayload = {
  /**
   * Text describing the function of the milestone
   */
  description: string;
  /**
   * Amount to be transferred upon completion of this milestone
   */
  amount: number;
  /**
   * Address where milestone proceeds will be sent to
   */
  receiver: string;
};

// ----------------- Initialize Escrow -----------------
/**
 * Single Release Initialize Escrow Payload
 */
export type InitializeSingleReleaseEscrowPayload = Omit<
  SingleReleaseEscrow,
  "contractId" | "balance" | "milestones"
> & {
  /**
   * Objectives to be completed to define the escrow as completed
   */
  milestones: SingleReleaseMilestonePayload[];
};

/**
 * Multi Release Initialize Escrow Payload
 */
export type InitializeMultiReleaseEscrowPayload = Omit<
  MultiReleaseEscrow,
  "contractId" | "balance" | "milestones"
> & {
  /**
   * Objectives to be completed to define the escrow as completed
   */
  milestones: MultiReleaseMilestonePayload[];
};

// ----------------- Update Escrow -----------------
/**
 * Single Release Update Escrow Payload
 */
export type UpdateSingleReleaseEscrowPayload = {
  /**
   * ID (address) that identifies the escrow contract
   */
  contractId: string;

  /**
   * Escrow data
   */
  escrow: Omit<SingleReleaseEscrow, "contractId" | "signer" | "balance"> & {
    /**
     * Whether the escrow is active. This comes from DB, not from the blockchain.
     */
    isActive?: boolean;
  };

  /**
   * Address of the user signing the contract transaction
   */
  signer: string;
};

/**
 * Multi Release Update Escrow Payload
 */
export type UpdateMultiReleaseEscrowPayload = {
  /**
   * ID (address) that identifies the escrow contract
   */
  contractId: string;

  /**
   * Escrow data
   */
  escrow: Omit<MultiReleaseEscrow, "contractId" | "signer" | "balance"> & {
    /**
     * Whether the escrow is active. This comes from DB, not from the blockchain.
     */
    isActive?: boolean;
  };

  /**
   * Address of the user signing the contract transaction
   */
  signer: string;
};

// ----------------- Change Milestone Status -----------------
/**
 * Change Milestone Status Payload, this can be a single-release or multi-release
 */
export type ChangeMilestoneStatusPayload = {
  /**
   * ID (address) that identifies the escrow contract
   */
  contractId: string;

  /**
   * Index of the milestone to be updated
   */
  milestoneIndex: string;

  /**
   * New status of the milestone
   */
  newStatus: string;

  /**
   * New evidence of work performed by the service provider.
   */
  newEvidence?: string;

  /**
   * Address of the entity providing the service.
   */
  serviceProvider: string;
};

// ----------------- Approve Milestone -----------------
/**
 * Approve Milestone Payload, this can be a single-release or multi-release
 */
export type ApproveMilestonePayload = Omit<
  ChangeMilestoneStatusPayload,
  "serviceProvider" | "newStatus"
> & {
  /**
   * Address of the entity requiring the service.
   */
  approver: string;
};

// ----------------- Start Dispute -----------------
/**
 * Single Release Start Dispute Payload. This starts a dispute for the entire escrow.
 */
export type SingleReleaseStartDisputePayload = {
  /**
   * ID (address) that identifies the escrow contract
   */
  contractId: string;

  /**
   * Address of the user signing the contract transaction
   */
  signer: string;
};

/**
 * Multi Release Start Dispute Payload. This starts a dispute for a specific milestone.
 */
export type MultiReleaseStartDisputePayload =
  SingleReleaseStartDisputePayload & {
    /**
     * Index of the milestone to be disputed
     */
    milestoneIndex: string;
  };

// ----------------- Resolve Dispute -----------------
/**
 * Resolve Dispute Payload
 */
export type SingleReleaseResolveDisputePayload = {
  /**
   * ID (address) that identifies the escrow contract
   */
  contractId: string;

  /**
   * Address in charge of resolving disputes within the escrow.
   */
  disputeResolver: string;

  /**
   * Distributions of the escrow amount to the receivers.
   */
  distributions: [
    {
      /**
       * Address of the receiver
       */
      address: string;
      /**
       * Amount to be transferred to the receiver. All the amount must be equal to the total amount of the escrow.
       */
      amount: number;
    },
  ];
};

/**
 * Multi Release Resolve Dispute Payload
 */
export type MultiReleaseResolveDisputePayload =
  SingleReleaseResolveDisputePayload & {
    /**
     * Index of the milestone to be resolved
     */
    milestoneIndex: string;
  };

// ----------------- Withdraw Remaining Funds -----------------
/**
 * Withdraw remaining funds
 */
export type WithdrawRemainingFundsPayload = SingleReleaseResolveDisputePayload;

// ----------------- Fund Escrow -----------------
/**
 * Fund Escrow Payload, this can be a single-release or multi-release
 */
export type FundEscrowPayload = {
  /**
   * Amount to be transferred upon completion of escrow milestones
   */
  amount: number;

  /**
   * ID (address) that identifies the escrow contract
   */
  contractId: string;

  /**
   * Address of the user signing the contract transaction
   */
  signer: string;
};

// ----------------- Get Escrows From Indexer -----------------
/**
 * Get Escrows From Indexer Params
 */
export type GetEscrowsFromIndexerParams = {
  /**
   * Page number. Pagination
   */
  page?: number;

  /**
   * Sorting direction. Sorting
   */
  orderDirection?: "asc" | "desc";

  /**
   * Order by property. Sorting
   */
  orderBy?: "createdAt" | "updatedAt" | "amount";

  /**
   * Created at = start date. Filtering
   */
  startDate?: string;

  /**
   * Created at = end date. Filtering
   */
  endDate?: string;

  /**
   * Max amount. Filtering
   */
  maxAmount?: number;

  /**
   * Min amount. Filtering
   */
  minAmount?: number;

  /**
   * Is active. Filtering
   */
  isActive?: boolean;

  /**
   * Escrow that you are looking for. Filtering
   */
  title?: string;

  /**
   * Engagement ID. Filtering
   */
  engagementId?: string;

  /**
   * Status of the single-release escrow. Filtering
   */
  status?: SingleReleaseEscrowStatus;

  /**
   * Type of the escrow. Filtering
   */
  type?: EscrowType;

  /**
   * If true, the escrows will be validated on the blockchain to ensure data consistency.
   * This performs an additional verification step to confirm that the escrow data
   * returned from the indexer matches the current state on the blockchain.
   * Use this when you need to ensure the most up-to-date and accurate escrow information.
   * If you active this param, your request will take longer to complete.
   */
  validateOnChain?: boolean;
};

export type GetEscrowsFromIndexerBySignerParams =
  GetEscrowsFromIndexerParams & {
    /**
     * Address of the user signing the contract transaction.
     */
    signer: string;
  };

export type GetEscrowsFromIndexerByRoleParams = GetEscrowsFromIndexerParams & {
  /**
   * Role of the user. Required
   */
  role: Role;

  /**
   * Address of the owner of the escrows. If you want to get all escrows from a specific role, you can use this parameter. But with this parameter, you can't use the signer parameter.
   */
  roleAddress: string;
};

export type GetEscrowFromIndexerByContractIdsParams = {
  /**
   * IDs (addresses) that identifies the escrow contracts.
   */
  contractIds: string[];

  /**
   * If true, the escrows will be validated on the blockchain to ensure data consistency.
   * This performs an additional verification step to confirm that the escrow data
   * returned from the indexer matches the current state on the blockchain.
   * Use this when you need to ensure the most up-to-date and accurate escrow information.
   * If you active this param, your request will take longer to complete.
   */
  validateOnChain?: boolean;
};

// ----------------- Release Funds -----------------
/**
 * Single Release Release Funds Payload
 */
export type SingleReleaseReleaseFundsPayload = {
  /**
   * ID (address) that identifies the escrow contract
   */
  contractId: string;

  /**
   * Address of the user in charge of releasing the escrow funds to the service provider.
   */
  releaseSigner: string;
};

/**
 * Multi Release Release Funds Payload
 */
export type MultiReleaseReleaseFundsPayload =
  SingleReleaseReleaseFundsPayload & {
    /**
     * Index of the milestone to be released
     */
    milestoneIndex: string;
  };

// ----------------- Get Balance -----------------
/**
 * Get Balance Params
 */
export type GetBalanceParams = {
  /**
   * Addresses of the escrows to get the balance
   */
  addresses: string[];
};

// ----------------- Update From Transaction Hash -----------------
/**
 * Payload for updating escrow data from a transaction hash.
 */
export type UpdateFromTxHashPayload = {
  /**
   * Transaction hash to be used for the update.
   */
  txHash: string;
};
```


# Deploy

### Single Release

```typescript
/**
 * Single Release Initialize Escrow Payload
 */
export type InitializeSingleReleaseEscrowPayload = {
  /**
   * Address of the user signing the contract transaction
   */
  signer: string;

  /**
   * Unique identifier for the escrow
   */
  engagementId: string;

  /**
   * Name of the escrow
   */
  title: string;

  /**
   * Roles that make up the escrow structure
   */
  roles: {
    /**
     * Address of the entity requiring the service.
     */
    approver: string;

    /**
     * Address of the entity providing the service.
     */
    serviceProvider: string;

    /**
     * Address of the entity that owns the escrow
     */
    platformAddress: string;

    /**
     * Address of the user in charge of releasing the escrow funds to the service provider.
     */
    releaseSigner: string;

    /**
     * Address in charge of resolving disputes within the escrow.
     */
    disputeResolver: string;

    /**
     * Address where escrow proceeds will be sent to
     */
    receiver: string;
  };

  /**
   * Text describing the function of the escrow
   */
  description: string;

  /**
   * Amount to be transferred upon completion of escrow milestones
   */
  amount: number;

  /**
   * Commission that the platform will receive when the escrow is completed
   */
  platformFee: number;

  /**
   * Flags validating certain escrow life states
   */
  flags?: {
    /**
     * Flag indicating that an escrow is in dispute.
     */
    disputed?: boolean;

    /**
     * Flag indicating that escrow funds have already been released.
     */
    released?: boolean;

    /**
     * Flag indicating that a disputed escrow has already been resolved.
     */
    resolved?: boolean;

    /**
     * Flag indicating whether a milestone has been approved by the approver.
     */
    approved?: boolean;
  };

  /**
   * Information on the trustline that will manage the movement of funds in escrow
   */
  trustline: {
    /**
     * Public address establishing permission to accept and use a specific token.
     */
    address: string;
    
    /**
     * Official abbreviation representing the token in wallets, exchanges, and documentation.
     */
    symbol: string;
  };

  /**
   * Objectives to be completed to define the escrow as completed
   */
  milestones: {
    /**
     * Text describing the function of the milestone
     */
    description: string;
  }[];
};
```

### Multi Release

```typescript
/**
 * Multi Release Initialize Escrow Payload
 */
export type InitializeMultiReleaseEscrowPayload = {
  /**
   * Address of the user signing the contract transaction
   */
  signer: string;

  /**
   * Unique identifier for the escrow
   */
  engagementId: string;

  /**
   * Name of the escrow
   */
  title: string;

  /**
   * Roles that make up the escrow structure (without receiver, as each milestone has its own receiver)
   */
  roles: {
    /**
     * Address of the entity requiring the service.
     */
    approver: string;

    /**
     * Address of the entity providing the service.
     */
    serviceProvider: string;

    /**
     * Address of the entity that owns the escrow
     */
    platformAddress: string;

    /**
     * Address of the user in charge of releasing the escrow funds to the service provider.
     */
    releaseSigner: string;

    /**
     * Address in charge of resolving disputes within the escrow.
     */
    disputeResolver: string;
  };

  /**
   * Text describing the function of the escrow
   */
  description: string;

  /**
   * Commission that the platform will receive when the escrow is completed
   */
  platformFee: number;

  /**
   * Information on the trustline that will manage the movement of funds in escrow
   */
  trustline: {
    /**
     * Public address establishing permission to accept and use a specific token.
     */
    address: string;
    
    /**
     * Official abbreviation representing the token in wallets, exchanges, and documentation.
     */
    symbol: string;
  };

  /**
   * Objectives to be completed to define the escrow as completed
   */
  milestones: {
    /**
     * Text describing the function of the milestone
     */
    description: string;
    /**
     * Amount to be transferred upon completion of this milestone
     */
    amount: number;
    /**
     * Address where milestone proceeds will be sent to
     */
    receiver: string;
  }[];
};
```


# Update Escrow

### Single Release

```typescript
/**
 * Single Release Update Escrow Payload
 */
export type UpdateSingleReleaseEscrowPayload = {
  /**
   * ID (address) that identifies the escrow contract
   */
  contractId: string;

  /**
   * Escrow data
   */
  escrow: {
    /**
   * Unique identifier for the escrow
   */
    engagementId: string;

    /**
     * Name of the escrow
     */
    title: string;

    /**
     * Roles that make up the escrow structure
     */
    roles: {
      /**
       * Address of the entity requiring the service.
       */
      approver: string;

      /**
       * Address of the entity providing the service.
       */
      serviceProvider: string;

      /**
       * Address of the entity that owns the escrow
       */
      platformAddress: string;

      /**
       * Address of the user in charge of releasing the escrow funds to the service provider.
       */
      releaseSigner: string;

      /**
       * Address in charge of resolving disputes within the escrow.
       */
      disputeResolver: string;

      /**
       * Address where escrow proceeds will be sent to
       */
      receiver: string;
    };

    /**
     * Text describing the function of the escrow
     */
    description: string;

    /**
     * Amount to be transferred upon completion of escrow milestones
     */
    amount: number;

    /**
     * Commission that the platform will receive when the escrow is completed
     */
    platformFee: number;

    /**
     * Objectives to be completed to define the escrow as completed
     */
    milestones: {
      /**
       * Text describing the function of the milestone.
       */
      description: string;

      /**
       * Milestone status. Ex: Approved, In dispute, etc...
       */
      status?: string;

      /**
       * Evidence of work performed by the service provider.
       */
      evidence?: string;

      /**
       * Approved flag, only if the escrow is single-release
       */
      approved?: boolean;
    }[];

    /**
     * Flags validating certain escrow life states
     */
    flags?: {
      /**
       * Flag indicating that an escrow is in dispute.
       */
      disputed?: boolean;

      /**
       * Flag indicating that escrow funds have already been released.
       */
      released?: boolean;

      /**
       * Flag indicating that a disputed escrow has already been resolved.
       */
      resolved?: boolean;

      /**
       * Flag indicating whether a milestone has been approved by the approver.
       */
      approved?: boolean;
    };

   /**
     * Information on the trustline that will manage the movement of funds in escrow
     */
    trustline: {   
     /**
       * Symbol of the token, example: USDC, EURC, etc...
       */
      symbol: string;
  
      /**
       * Public address establishing permission to accept and use a specific token.
       */
      address: string;
    };

    /**
     * Whether the escrow is active. This comes from DB, not from the blockchain.
     */
    isActive?: boolean;
  };

  /**
   * Address of the user signing the contract transaction
   */
  signer: string;
};
```

### Multi Release

```typescript
/**
 * Multi Release Update Escrow Payload
 */
export type UpdateMultiReleaseEscrowPayload = {
  /**
   * ID (address) that identifies the escrow contract
   */
  contractId: string;

  /**
   * Escrow data
   */
  escrow: {
    /**
     * Unique identifier for the escrow
     */
    engagementId: string;

    /**
     * Name of the escrow
     */
    title: string;

    /**
     * Roles that make up the escrow structure (without receiver, as each milestone has its own receiver)
     */
    roles: {
      /**
       * Address of the entity requiring the service.
       */
      approver: string;

      /**
       * Address of the entity providing the service.
       */
      serviceProvider: string;

      /**
       * Address of the entity that owns the escrow
       */
      platformAddress: string;

      /**
       * Address of the user in charge of releasing the escrow funds to the service provider.
       */
      releaseSigner: string;

      /**
       * Address in charge of resolving disputes within the escrow.
       */
      disputeResolver: string;
    };

    /**
     * Text describing the function of the escrow
     */
    description: string;

    /**
     * Commission that the platform will receive when the escrow is completed
     */
    platformFee: number;

    /**
     * Objectives to be completed to define the escrow as completed
     */
    milestones: {
      /**
       * Text describing the function of the milestone.
       */
      description: string;

      /**
       * Milestone status. Ex: Approved, In dispute, etc...
       */
      status?: string;

      /**
       * Evidence of work performed by the service provider.
       */
      evidence?: string;

      /**
       * Amount to be transferred upon completion of this milestone
       */
      amount: number;

      /**
       * Address where milestone proceeds will be sent to
       */
      receiver: string;

      /**
       * Flags validating certain milestone life states, only if the escrow is multi-release
       */
      flags?: {
        /**
         * Flag indicating that an escrow is in dispute.
         */
        disputed?: boolean;

        /**
         * Flag indicating that escrow funds have already been released.
         */
        released?: boolean;

        /**
         * Flag indicating that a disputed escrow has already been resolved.
         */
        resolved?: boolean;

        /**
         * Flag indicating whether a milestone has been approved by the approver.
         */
        approved?: boolean;
      };
    }[];

    /**
     * Information on the trustline that will manage the movement of funds in escrow
     */
    trustline: {   
     /**
       * Symbol of the token, example: USDC, EURC, etc...
       */
      symbol: string;
  
      /**
       * Public address establishing permission to accept and use a specific token.
       */
      address: string;
    };

    /**
     * Whether the escrow is active. This comes from DB, not from the blockchain.
     */
    isActive?: boolean;
  };

  /**
   * Address of the user signing the contract transaction
   */
  signer: string;
};
```


# Fund Escrow

### Single & Multi Release

```typescript
/**
 * Fund Escrow Payload, this can be a single-release or multi-release
 */
export type FundEscrowPayload = {
  /**
   * Amount to be transferred upon completion of escrow milestones
   */
  amount: number;

  /**
   * ID (address) that identifies the escrow contract
   */
  contractId: string;

  /**
   * Address of the user signing the contract transaction
   */
  signer: string;
};
```


# Approve Milestone

### Single & Multi Release

```typescript
/**
 * Approve Milestone Payload, this can be a single-release or multi-release
 */
export type ApproveMilestonePayload = {
  /**
   * ID (address) that identifies the escrow contract
   */
  contractId: string;

  /**
   * Index of the milestone to be updated
   */
  milestoneIndex: string;

  /**
   * New evidence of work performed by the service provider.
   */
  newEvidence?: string;

  /**
   * Address of the entity requiring the service.
   */
  approver: string;
};
```


# Change Milestone Status

### Single & Multi Release

```typescript
/**
 * Change Milestone Status Payload, this can be a single-release or multi-release
 */
export type ChangeMilestoneStatusPayload = {
  /**
   * ID (address) that identifies the escrow contract
   */
  contractId: string;

  /**
   * Index of the milestone to be updated
   */
  milestoneIndex: string;

  /**
   * New status of the milestone
   */
  newStatus: string;

  /**
   * New evidence of work performed by the service provider.
   */
  newEvidence?: string;

  /**
   * Address of the entity providing the service.
   */
  serviceProvider: string;
};
```


# Release Funds

### Single Release

```typescript
/**
 * Single Release Release Funds Payload
 */
export type SingleReleaseReleaseFundsPayload = {
  /**
   * ID (address) that identifies the escrow contract
   */
  contractId: string;

  /**
   * Address of the user in charge of releasing the escrow funds to the service provider.
   */
  releaseSigner: string;
};
```

### Multi Release

```typescript
/**
 * Multi Release Release Funds Payload
 */
export type MultiReleaseReleaseFundsPayload = {
  /**
   * ID (address) that identifies the escrow contract
   */
  contractId: string;

  /**
   * Address of the user in charge of releasing the escrow funds to the service provider.
   */
  releaseSigner: string;

  /**
   * Index of the milestone to be released
   */
  milestoneIndex: string;
};
```


# Start Dispute

### Single Release

```typescript
/**
 * Single Release Start Dispute Payload. This starts a dispute for the entire escrow.
 */
export type SingleReleaseStartDisputePayload = {
  /**
   * ID (address) that identifies the escrow contract
   */
  contractId: string;

  /**
   * Address of the user signing the contract transaction
   */
  signer: string;
};
```

### Multi Release

```typescript
/**
 * Multi Release Start Dispute Payload. This starts a dispute for a specific milestone.
 */
export type MultiReleaseStartDisputePayload = {
  /**
   * ID (address) that identifies the escrow contract
   */
  contractId: string;

  /**
   * Address of the user signing the contract transaction
   */
  signer: string;

  /**
   * Index of the milestone to be disputed
   */
  milestoneIndex: string;
};
```


# Resolve Dispute

### Single Release

```typescript
/**
 * Resolve Dispute Payload
 */
export type SingleReleaseResolveDisputePayload = {
  /**
   * ID (address) that identifies the escrow contract
   */
  contractId: string;

  /**
   * Address in charge of resolving disputes within the escrow.
   */
  disputeResolver: string;

  /**
   * Distributions of the escrow amount to the receivers.
   */
  distributions: [
    {
      /**
       * Address of the receiver
       */
      address: string;
      /**
       * Amount to be transferred to the receiver. All the amount must be equal to the total amount of the escrow.
       */
      amount: number;
    },
  ];
};
```

### Multi Release

```typescript
/**
 * Multi Release Resolve Dispute Payload
 */
export type MultiReleaseResolveDisputePayload = {
  /**
   * ID (address) that identifies the escrow contract
   */
  contractId: string;

  /**
   * Address in charge of resolving disputes within the escrow.
   */
  disputeResolver: string;

  /**
   * Distributions of the escrow amount to the receivers.
   */
  distributions: [
    {
      /**
       * Address of the receiver
       */
      address: string;
      /**
       * Amount to be transferred to the receiver. All the amount must be equal to the total amount of the escrow.
       */
      amount: number;
    },
  ];

  /**
   * Index of the milestone to be resolved
   */
  milestoneIndex: string;
};
```


# Withdraw Remaining Funds

### Multi Release Only

```typescript
/**
 * Withdraw remaining funds
 */
export type WithdrawRemainingFundsPayload = {
  /**
   * ID (address) that identifies the escrow contract
   */
  contractId: string;

  /**
   * Address in charge of resolving disputes within the escrow.
   */
  disputeResolver: string;

  /**
   * Distributions of the escrow amount to the receivers.
   */
  distributions: [
    {
      /**
       * Address of the receiver
       */
      address: string;
      /**
       * Amount to be transferred to the receiver. All the amount must be equal to the total amount of the escrow.
       */
      amount: number;
    },
  ];
};

```


# Get Balances

### Params

```typescript
/**
 * Get Balance Params
 */
export type GetBalanceParams = {
  /**
   * Addresses of the escrows to get the balance
   */
  addresses: string[];
};
```


# Get Escrows by Contract ID

### Params

```typescript
/**
 * Get Escrow From Indexer By Contract Ids Params
 */
export type GetEscrowFromIndexerByContractIdsParams = {
  /**
   * IDs (addresses) that identifies the escrow contracts.
   */
  contractIds: string[];

  /**
   * If true, the escrows will be validated on the blockchain to ensure data consistency.
   * This performs an additional verification step to confirm that the escrow data
   * returned from the indexer matches the current state on the blockchain.
   * Use this when you need to ensure the most up-to-date and accurate escrow information.
   * If you active this param, your request will take longer to complete.
   */
  validateOnChain?: boolean;
};
```


# Get Escrows by Signer

### Params

```typescript
/**
 * Get Escrows From Indexer By Signer Params
 */
export type GetEscrowsFromIndexerBySignerParams = {
  /**
   * Page number. Pagination
   */
  page?: number;

  /**
   * Sorting direction. Sorting
   */
  orderDirection?: "asc" | "desc";

  /**
   * Order by property. Sorting
   */
  orderBy?: "createdAt" | "updatedAt" | "amount";

  /**
   * Created at = start date. Filtering
   */
  startDate?: string;

  /**
   * Created at = end date. Filtering
   */
  endDate?: string;

  /**
   * Max amount. Filtering
   */
  maxAmount?: number;

  /**
   * Min amount. Filtering
   */
  minAmount?: number;

  /**
   * Is active. Filtering
   */
  isActive?: boolean;

  /**
   * Escrow that you are looking for. Filtering
   */
  title?: string;

  /**
   * Engagement ID. Filtering
   */
  engagementId?: string;

  /**
   * Status of the single-release escrow. Filtering
   */
  status?: SingleReleaseEscrowStatus;

  /**
   * Type of the escrow. Filtering
   */
  type?: "single-release" | "multi-release";

  /**
   * If true, the escrows will be validated on the blockchain to ensure data consistency.
   * This performs an additional verification step to confirm that the escrow data
   * returned from the indexer matches the current state on the blockchain.
   * Use this when you need to ensure the most up-to-date and accurate escrow information.
   * If you active this param, your request will take longer to complete.
   */
  validateOnChain?: boolean;

  /**
   * Address of the user signing the contract transaction.
   */
  signer: string;
};
```


# Get Escrows by Role

### Params

```typescript
/**
 * Get Escrows From Indexer By Role Params
 */
export type GetEscrowsFromIndexerByRoleParams = {
  /**
   * Page number. Pagination
   */
  page?: number;

  /**
   * Sorting direction. Sorting
   */
  orderDirection?: "asc" | "desc";

  /**
   * Order by property. Sorting
   */
  orderBy?: "createdAt" | "updatedAt" | "amount";

  /**
   * Created at = start date. Filtering
   */
  startDate?: string;

  /**
   * Created at = end date. Filtering
   */
  endDate?: string;

  /**
   * Max amount. Filtering
   */
  maxAmount?: number;

  /**
   * Min amount. Filtering
   */
  minAmount?: number;

  /**
   * Is active. Filtering
   */
  isActive?: boolean;

  /**
   * Escrow that you are looking for. Filtering
   */
  title?: string;

  /**
   * Engagement ID. Filtering
   */
  engagementId?: string;

  /**
   * Status of the single-release escrow. Filtering
   */
  status?: SingleReleaseEscrowStatus;

  /**
   * Type of the escrow. Filtering
   */
  type?: EscrowType;

  /**
   * If true, the escrows will be validated on the blockchain to ensure data consistency.
   * This performs an additional verification step to confirm that the escrow data
   * returned from the indexer matches the current state on the blockchain.
   * Use this when you need to ensure the most up-to-date and accurate escrow information.
   * If you active this param, your request will take longer to complete.
   */
  validateOnChain?: boolean;

  /**
   * Role of the user. Required
   */
  role: Role;

  /**
   * Address of the owner of the escrows. If you want to get all escrows from a specific role, you can use this parameter. But with this parameter, you can't use the signer parameter.
   */
  roleAddress: string;
};

```


# Responses

### Escrow's Response Entity

```typescript
import { Date, EscrowType, Status } from "./types";
import {
  Flags,
  MultiReleaseEscrow,
  MultiReleaseMilestone,
  Roles,
  SingleReleaseEscrow,
  SingleReleaseMilestone,
  Trustline,
} from "./types.entity";

/**
 * Escrow's Response like fund, release, change, etc ...
 */
export type EscrowRequestResponse = {
  /**
   * Status of the request
   */
  status: Status;

  /**
   * Unsigned transaction
   */
  unsignedTransaction?: string;
};

/**
 * Send Transaction Response
 */
export type SendTransactionResponse = {
  /**
   * Status of the request
   */
  status: Status;

  /**
   * Message of the request
   */
  message: string;
};

/**
 * Initialize Escrow Response
 */
export type InitializeSingleReleaseEscrowResponse = EscrowRequestResponse & {
  /**
   * ID (address) that identifies the escrow contract
   */
  contractId: string;

  /**
   * Escrow data
   */
  escrow: SingleReleaseEscrow;

  /**
   * Message of the request
   */
  message: string;
};

/**
 * Initialize Multi Release Escrow Response
 */
export type InitializeMultiReleaseEscrowResponse =
  InitializeSingleReleaseEscrowResponse & {
    /**
     * Escrow data
     */
    escrow: MultiReleaseEscrow;
  };

/**
 * Update Escrow Response
 */
export type UpdateSingleReleaseEscrowResponse =
  InitializeSingleReleaseEscrowResponse;

/**
 * Update Multi Release Escrow Response
 */
export type UpdateMultiReleaseEscrowResponse =
  InitializeMultiReleaseEscrowResponse;

/**
 * Get Balances Response
 */
export type GetEscrowBalancesResponse = {
  /**
   * Address of the escrow
   */
  address: string;

  /**
   * Balance of the escrow
   */
  balance: number;
};

/**
 * Get Escrows From Indexer Response
 */
export type GetEscrowsFromIndexerResponse = {
  signer?: string;
  contractId?: string;
  engagementId: string;
  title: string;
  roles: Roles;
  description: string;
  amount: number;
  platformFee: number;
  balance?: number;
  milestones:
    | SingleReleaseMilestone[]
    | (MultiReleaseMilestone[] & { disputeStartedBy: Roles });
  flags?: Flags;
  trustline: Trustline & { name: string };
  receiverMemo?: number;
  disputeStartedBy?: string;
  fundedBy?: string;
  isActive?: boolean;
  approverFunds?: string;
  receiverFunds?: string;
  user: string;
  createdAt: Date;
  updatedAt: Date;
  type: EscrowType;
};

/**
 * Response for updating escrow from transaction hash
 */
export type UpdateFromTxHashResponse = {
  /**
   * Status of the request
   */
  status: "SUCCESS" | "FAILED";

  /**
   * Message describing the result
   */
  message: string;
};
```


# Errors

## Errors Entity

```typescript
import { ApiErrorTypes } from "@/errors/enums/error.enum";

/**
 * Types for Error response
 */
export type ErrorResponse = {
  message: string;
  code: number;
  type: ApiErrorTypes;
};

/**
 * Types for TW errors
 */
export type ApiError = Pick<ErrorResponse, "message" | "code">;

/**
 * Types for Wallet errors
 */
export type WalletError = Pick<ErrorResponse, "message" | "code">;

/**
 * Types for Request errors
 */
export type RequestError = ApiError | Error | WalletError;

```


# Stellar Wallet Kit - Quick Integration

## **Building a Stellar Wallet Management System**

This guide will walk you through creating a comprehensive wallet management system for Stellar blockchain integration in your React/Next.js application. The system provides secure wallet connection, disconnection, and state management with persistence.

### **Overview**

The system consists of three main components:

1. **Wallet Provider** - Global state management for wallet information
2. **Wallet Hook** - Business logic for wallet operations
3. **Wallet Kit Configuration** - Stellar blockchain integration setup

### **Step 1: Install Dependencies**

First, install the required Stellar Wallet Kit package:

```bash
npm install @creit.tech/stellar-wallets-kit
```

### **Step 2: Configure the Stellar Wallet Kit**

Create a configuration file that sets up the Stellar Wallet Kit with support for multiple wallet types:

```tsx
import {
  StellarWalletsKit,
  WalletNetwork,
  FREIGHTER_ID,
  AlbedoModule,
  FreighterModule,
} from "@creit.tech/stellar-wallets-kit";

/**
 * Main configuration for Stellar Wallet Kit
 * This kit supports multiple wallet types including Freighter and Albedo
 * Configure for TESTNET during development and MAINNET for production
 */
export const kit: StellarWalletsKit = new StellarWalletsKit({
  network: WalletNetwork.TESTNET,
  selectedWalletId: FREIGHTER_ID,
  modules: [new FreighterModule(), new AlbedoModule()],
});

/**
 * Interface for transaction signing parameters
 */
interface signTransactionProps {
  unsignedTransaction: string;
  address: string;
}

/**
 * Sign a Stellar transaction using the connected wallet
 * This function handles the signing process and returns the signed transaction
 * 
 * @param unsignedTransaction - The XDR string of the unsigned transaction
 * @param address - The wallet address that will sign the transaction
 * @returns Promise<string> - The signed transaction XDR
 */
export const signTransaction = async ({
  unsignedTransaction,
  address,
}: signTransactionProps): Promise<string> => {
  const { signedTxXdr } = await kit.signTransaction(unsignedTransaction, {
    address,
    networkPassphrase: WalletNetwork.TESTNET,
  });

  return signedTxXdr;
};
```

### **Step 3: Create the Wallet Context Provider**

The Wallet Provider manages global wallet state and persists information in localStorage for better user experienc

```tsx
"use client";

import {
  createContext,
  useContext,
  useState,
  useEffect,
  ReactNode,
} from "react";

/**
 * Type definition for the wallet context
 * Contains wallet address, name, and functions to manage wallet state
 */
type WalletContextType = {
  walletAddress: string | null;
  walletName: string | null;
  setWalletInfo: (address: string, name: string) => void;
  clearWalletInfo: () => void;
};

/**
 * Create the React context for wallet state management
 */
const WalletContext = createContext<WalletContextType | undefined>(undefined);

/**
 * Wallet Provider component that wraps the application
 * Manages wallet state and provides wallet information to child components
 * Automatically loads saved wallet information from localStorage on initialization
 */
export const WalletProvider = ({ children }: { children: ReactNode }) => {
  const [walletAddress, setWalletAddress] = useState<string | null>(null);
  const [walletName, setWalletName] = useState<string | null>(null);

  /**
   * Load saved wallet information from localStorage when the component mounts
   * This ensures the wallet state persists across browser sessions
   */
  useEffect(() => {
    const storedAddress = localStorage.getItem("walletAddress");
    const storedName = localStorage.getItem("walletName");

    if (storedAddress) setWalletAddress(storedAddress);
    if (storedName) setWalletName(storedName);
  }, []);

  /**
   * Set wallet information and save it to localStorage
   * This function is called when a wallet is successfully connected
   * 
   * @param address - The wallet's public address
   * @param name - The name/identifier of the wallet (e.g., "Freighter", "Albedo")
   */
  const setWalletInfo = (address: string, name: string) => {
    setWalletAddress(address);
    setWalletName(name);
    localStorage.setItem("walletAddress", address);
    localStorage.setItem("walletName", name);
  };

  /**
   * Clear wallet information and remove it from localStorage
   * This function is called when disconnecting a wallet
   */
  const clearWalletInfo = () => {
    setWalletAddress(null);
    setWalletName(null);
    localStorage.removeItem("walletAddress");
    localStorage.removeItem("walletName");
  };

  return (
    <WalletContext.Provider
      value={{ walletAddress, walletName, setWalletInfo, clearWalletInfo }}
    >
      {children}
    </WalletContext.Provider>
  );
};

/**
 * Custom hook to access the wallet context
 * Provides wallet state and functions to components
 * Throws an error if used outside of WalletProvider
 */
export const useWalletContext = () => {
  const context = useContext(WalletContext);
  if (!context) {
    throw new Error("useWalletContext must be used within WalletProvider");
  }
  return context;
};
```

### **Step 4: Create the Wallet Hook**

The wallet hook encapsulates all the business logic for wallet operations, providing a clean interface for components:

```tsx
import { kit } from "@/config/wallet-kit";
import { useWalletContext } from "@/providers/wallet.provider";
import { ISupportedWallet } from "@creit.tech/stellar-wallets-kit";

/**
 * Custom hook that provides wallet connection and disconnection functionality
 * Integrates with the Stellar Wallet Kit and manages wallet state through context
 */
export const useWallet = () => {
  // Get wallet management functions from the context
  const { setWalletInfo, clearWalletInfo } = useWalletContext();

  /**
   * Connect to a Stellar wallet using the Wallet Kit
   * Opens a modal for wallet selection and handles the connection process
   * Automatically sets wallet information in the context upon successful connection
   */
  const connectWallet = async () => {
    await kit.openModal({
      modalTitle: "Connect to your favorite wallet",
      onWalletSelected: async (option: ISupportedWallet) => {
        // Set the selected wallet as the active wallet
        kit.setWallet(option.id);

        // Get the wallet address and name
        const { address } = await kit.getAddress();
        const { name } = option;

        // Store wallet information in the context and localStorage
        setWalletInfo(address, name);
      },
    });
  };

  /**
   * Disconnect from the current wallet
   * Clears wallet information from the context and localStorage
   * Disconnects the wallet from the Stellar Wallet Kit
   */
  const disconnectWallet = async () => {
    await kit.disconnect();
    clearWalletInfo();
  };

  /**
   * Handle wallet connection with error handling
   * Wraps the connectWallet function in a try-catch block for better error management
   */
  const handleConnect = async () => {
    try {
      await connectWallet();
    } catch (error) {
      console.error("Error connecting wallet:", error);
      // You can add additional error handling here, such as showing user notifications
    }
  };

  /**
   * Handle wallet disconnection with error handling
   * Wraps the disconnectWallet function in a try-catch block for better error management
   */
  const handleDisconnect = async () => {
    try {
      await disconnectWallet();
    } catch (error) {
      console.error("Error disconnecting wallet:", error);
      // You can add additional error handling here, such as showing user notifications
    }
  };

  return {
    connectWallet,
    disconnectWallet,
    handleConnect,
    handleDisconnect,
  };
};
```

### **Step 5: Integrate the Provider in Your App**

Wrap your application with the WalletProvider to enable wallet state management throughout your app:

```tsx
import { WalletProvider } from "@/providers/wallet.provider";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <WalletProvider>
          {children}
        </WalletProvider>
      </body>
    </html>
  );
}
```

### **Step 6: Use the Wallet Hook in Components**

Now you can use the wallet functionality in any component. Here's an example of a wallet connection button:

```tsx
import { useWallet } from "@/hooks/wallet.hook";
import { useWalletContext } from "@/providers/wallet.provider";

/**
 * Wallet connection/disconnection button component
 * Shows different states based on wallet connection status
 */
export const WalletButton = () => {
  const { handleConnect, handleDisconnect } = useWallet();
  const { walletAddress, walletName } = useWalletContext();

  // If wallet is connected, show disconnect option
  if (walletAddress) {
    return (
      <div className="flex items-center gap-4">
        <div className="text-sm">
          <p className="font-medium">Connected: {walletName}</p>
          <p className="text-gray-500">{walletAddress}</p>
        </div>
        <button 
          onClick={handleDisconnect}
          className="px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600"
        >
          Disconnect
        </button>
      </div>
    );
  }

  // If wallet is not connected, show connect option
  return (
    <button 
      onClick={handleConnect}
      className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
    >
      Connect Wallet
    </button>
  );
};
```

### **Key Features and Benefits**

#### **State Persistence**

* Wallet information is automatically saved to localStorage
* Users don't need to reconnect their wallet every time they visit your app
* Seamless user experience across browser sessions

#### **Multi-Wallet Support**

* Supports multiple Stellar wallet types (Freighter, Albedo, etc.)
* Easy to add new wallet modules as they become available
* Users can choose their preferred wallet

#### **Error Handling**

* Comprehensive error handling for wallet operations
* Graceful fallbacks when wallet operations fail
* Easy to extend with custom error notifications

#### **Type Safety**

* Full TypeScript support with proper type definitions
* IntelliSense support for better development experience
* Compile-time error checking for wallet operations

#### **Context-Based Architecture**

* Clean separation of concerns between state management and business logic
* Easy to access wallet state from any component
* Centralized wallet state management

### **Configuration Options**

#### **Network Selection**

* **TESTNET**: Use during development and testing
* **MAINNET**: Use for production applications


# Introduction

How to get started in Trustless Work API REST

### What is the Trustless Work API?

The **Trustless Work REST API** lets you create and manage **decentralized escrow contracts** on **Stellar** using **Soroban** smart contracts.

Use it to deploy escrows, fund them, track milestones, and release funds.

### Base URLs

{% tabs %}
{% tab title="Mainnet" %}
{% code title="Base URL (Mainnet)" %}

```
https://api.trustlesswork.com
```

{% endcode %}
{% endtab %}

{% tab title="Testnet" %}
{% code title="Base URL (Testnet)" %}

```
https://dev.api.trustlesswork.com
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Core capabilities

* **Deploy escrows** with roles, milestones, and conditions.
* **Fund escrows** using Stellar assets (example: USDC).
* **Approve / update milestones** to drive releases.
* **Dispute and resolution** flows (escrow-level or milestone-level).
* **Release funds** only when conditions are met.
* **Query status** for escrows, milestones, and balances.

### Escrow types

1. **Single-release escrow**
   * One release action for the full amount.
2. **Multi-release escrow**
   * Multiple milestone payouts.
   * Each milestone can be approved, disputed, and released independently.

### Rate limits

{% hint style="warning" %}
Limit: **50 requests per 60 seconds** per client.
{% endhint %}

### Transactions, signing, and permissions

{% hint style="info" %}
Most write endpoints return **unsigned XDR**.\
You must sign client-side with the correct role wallet.
{% endhint %}

Actions are **role-gated** (approve, dispute, resolve, release).

### Endpoint map (high level)

Use Swagger for the full spec. These groups cover most integrations:

#### Deployment

* `/deployer/single-release`
* `/deployer/multi-release`

#### Funding

* `/escrow/{type}/fund-escrow`

#### Milestones

* `/escrow/{type}/approve-milestone`
* `/escrow/{type}/change-milestone-status`

#### Release

* `/escrow/{type}/release-funds` (single)
* `/escrow/{type}/release-milestone-funds` (multi)

#### Disputes

* `/escrow/{type}/dispute-escrow`
* `/escrow/{type}/resolve-dispute`
* `/escrow/{type}/dispute-milestone` (multi)
* `/escrow/{type}/resolve-milestone-dispute` (multi)

#### Updates

* `/escrow/{type}/update-escrow`

#### Query / helpers

* `/escrow/get-multiple-escrow-balance`
* `/helper/get-escrows-by-signer`
* `/helper/get-escrows-by-role`
* `/helper/set-trustline`
* `/helper/send-transaction`

### Fees

Mainnet charges a **0.3% protocol fee**.

### API docs (Swagger)

{% tabs %}
{% tab title="Mainnet" %}
{% embed url="<https://api.trustlesswork.com/docs>" %}
{% endtab %}

{% tab title="Testnet" %}
{% embed url="<https://dev.api.trustlesswork.com/docs>" %}
{% endtab %}
{% endtabs %}

### Dev resources

* Dev map: <https://www.trustlesswork.com/developers>

### GitHub repository

{% embed url="<https://github.com/Trustless-Work>" %}


# Single Release Escrow

Single-Release Escrow is a type in which all your funds are released only once, either with the resolution of a dispute or by completing all the milestones defined for it.

The Deploy endpoints allow users to deploy escrows efficiently. These endpoints provide the way to initialize escrows in the Stellar's Blockchain.

**Key Components**

* **Initial Fund Lockup**: Upon contract initiation, the escrow amoun plus the platform fee (“platformFee”) is deposited into an escrow account.
* **Flags**: The escrow status is interpreted by means of these flags: (`approved`, `dispute`, `released`, `resolved`).
* **Primary Roles**:
  * **Service Provider**: Delivers the deliverable corresponding to each milestone.
  * **Approver**: Verifies and approves a milestone before authorizing the release of funds.
  * **Dispute Resolver**: Intervenes in case of disagreement and decides whether to release or refund the locked amount.
  * **Receiver**: The final recipient of the funds if different from the Service Provider.

**Brief Workflow**

1. An escrow is initialized by defining all the necessary escrow properties.
2. The Service Provider completes a milestone and requests approval.
3. The approver reviews the deliverable; if approved, signs a transaction that releases the amount allocated as escrow reward (minus the platform and Trustless Work fee).
4. The Stellar network executes the transaction and transfers the payment to the Service Provider or the configured Receiver.
5. If a dispute arises, the Dispute Resolver evaluates the evidence and, upon signing their decision, marks the escrow as resolved to release or refund the corresponding funds.

This model protects all parties: the client knows that funds are available but cannot be released without validation, and the service provider receives payment upon completion of all milestones and the milestones themselves being approved by the approver, leveraging Stellar's transparency and immutability.


# Deploy

Deploy the escrow contract and define the escrow properties.

### Headers

<table><thead><tr><th width="366">Name</th><th>Value</th></tr></thead><tbody><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>x-api-key</td><td><code>&#x3C;token></code></td></tr></tbody></table>

### Milestone

| Name        | Type                             | Description                                                           |
| ----------- | -------------------------------- | --------------------------------------------------------------------- |
| description | string                           | Text describing the function of the milestone                         |
| status      | string (Default value: "peding") | Milestone status. Ex: Approved, In dispute, etc...                    |
| approved    | boolean (Default value: false)   | Flag indicating whether a milestone has been approved by the approver |

### Roles:

| Name             | Type   | Description                                                                          |
| ---------------- | ------ | ------------------------------------------------------------------------------------ |
| approver         | string | Address of the entity requiring the service.                                         |
| serviceProvider  | string | Address of the entity providing the service.                                         |
| plataformAddress | string | Address of the entity that owns the escrow                                           |
| releaseSigner    | string | Address of the user in charge of releasing the escrow funds to the service provider. |
| disputeResolver  | string | Address in charge of resolving disputes within the escrow.                           |
| receiver         | string | Address where escrow proceeds will be sent to                                        |

### Trustline:

| Name    | Type   | Description                                                                            |
| ------- | ------ | -------------------------------------------------------------------------------------- |
| address | string | Public address establishing permission to accept and use a specific token.             |
| symbol  | string | Official abbreviation representing the token in wallets, exchanges, and documentation. |

### Initialize Escrow

## POST /deployer/single-release

>

```json
{"openapi":"3.0.0","info":{"title":"Trustless Work API","version":"1.0"},"security":[{}],"paths":{"/deployer/single-release":{"post":{"operationId":"DeployerController_deploySingleReleaseContract","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SingleReleaseContract"}}}},"responses":{"201":{"description":"This endpoint returns an unsigned transaction in XDR format. This XDR is then used to sign the transaction using the “/helper/send-transaction” endpoint.","content":{"application/json":{}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized access"},"429":{"description":"Too Many Requests"},"500":{"description":"Possible errors:\n- Amount cannot be zero\n- Escrow already initialized\n- The platform fee cannot exceed 99%\n- Escrow initialized without milestone\n- Cannot define more than 50 milestones in an escrow\n- All flags (approved, disputed, released) must be false in order to execute this function\n- An unexpected error occurred","content":{"application/json":{}}}},"tags":["Deployer"]}}},"components":{"schemas":{"SingleReleaseContract":{"type":"object","properties":{"signer":{"type":"string","description":"Entity that signs the transaction that deploys and initializes the escrow"},"engagementId":{"type":"string","description":"Unique identifier for the escrow"},"title":{"type":"string","description":"Name of the escrow"},"description":{"type":"string","description":"Text describing the function of the escrow"},"roles":{"description":"Roles that make up the escrow structure","type":"array","items":{"type":"object"}},"amount":{"type":"number","description":"Amount to be transferred upon completion of escrow milestones"},"platformFee":{"type":"number","description":"Commission that the platform will receive when the escrow is completed"},"milestones":{"description":"Objectives to be completed to define the escrow as completed. (In this case it is not necessary to send the properties “approvedFlag” and “status” inside the objects of these milestones)","type":"array","items":{"type":"object"}},"trustline":{"description":"Information on the trustline that will manage the movement of funds in escrow","type":"array","items":{"type":"object"}}},"required":["signer","engagementId","title","description","roles","amount","platformFee","milestones","trustline"]}}}}
```

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

### **What this Endpoint returns?**

This endpoint returns the transaction unsigned so that the transaction can be signed by means of a customer wallet.

### Use Example:

<pre class="language-typescript"><code class="lang-typescript">import axios from "axios";

const http = axios.create({
  baseURL: "https://dev.api.trustlesswork.com",
  timeout: 10000,
  headers: {
    "Content-Type": "application/json",
    "x-api-key": your_api_key,
  },
});

export const useExample = async () => {
    // Get the signer address
    const { address } = await kit.getAddress();

    // Execute the endpoint
<strong>    const response = await http.post(
</strong>      "/deployer/single-release",
      {
        // body requested for the endpoint
      },
    );
    
    // Get the unsigned transaction hash
    const { unsignedTransaction } = response.data;

    // Sign the transaction by wallet
    const { signedTxXdr } = await signTransaction(unsignedTransaction, {
      address,
      networkPassphrase: WalletNetwork.TESTNET,
    });

    // Send the transaction to Stellar Network
    const tx = await http.post("/helper/send-transaction", {
      signedXdr: signedTxXdr,
    });

    const { data } = tx;

    return data; 
}
</code></pre>


# Fund Escrow

Allows users to deposit funds into an existing escrow contract, securing them until the agreed conditions are met.

### **Headers**

<table><thead><tr><th width="366">Name</th><th>Value</th></tr></thead><tbody><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>x-api-key</td><td><code>&#x3C;token></code></td></tr></tbody></table>

### **Open API**

## POST /escrow/single-release/fund-escrow

>

```json
{"openapi":"3.0.0","info":{"title":"Trustless Work API","version":"1.0"},"security":[{}],"paths":{"/escrow/single-release/fund-escrow":{"post":{"operationId":"SingleReleaseController_fundEscrow","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FundEscrow"}}}},"responses":{"201":{"description":"This endpoint returns an unsigned transaction in XDR format. This XDR is then used to sign the transaction using the “/helper/send-transaction” endpoint.","content":{"application/json":{}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized access"},"429":{"description":"Too Many Requests"},"500":{"description":"Possible errors:\n- Amount cannot be equal to or less than zero\n- The provided escrow properties do not match the stored escrow\n- An unexpected error occurred","content":{"application/json":{}}}},"tags":["Single Release"]}}},"components":{"schemas":{"FundEscrow":{"type":"object","properties":{"contractId":{"type":"string","description":"ID (address) that identifies the escrow contract"},"signer":{"type":"string","description":"Entity that signs the transaction that deploys and initializes the escrow"},"amount":{"type":"number","description":"Amount to transfer to the escrow contract"}},"required":["contractId","signer","amount"]}}}}
```

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

### **What this Endpoint returns?**

This endpoint returns the transaction unsigned so that the transaction can be signed by means of a customer wallet.

### Use Example:

```typescript
import axios from "axios";

const http = axios.create({
  baseURL: "https://dev.api.trustlesswork.com",
  timeout: 10000,
  headers: {
    "Content-Type": "application/json",
    "x-api-key": your_api_key,
  },
});

export const useExample = async () => {
    // Get the signer address
    const { address } = await kit.getAddress();

    const response = await http.post(
      "/escrow/single-release/fund-escrow",
      {
        // body requested for the endpoint
      },
    ); 
    
    // Get the unsigned transaction hash
    const { unsignedTransaction } = response.data;

    // Sign the transaction by wallet
    const { signedTxXdr } = await signTransaction(unsignedTransaction, {
      address,
      networkPassphrase: WalletNetwork.TESTNET,
    });

    // Send the transaction to Stellar Network
    const tx = await http.post("/helper/send-transaction", {
      signedXdr: signedTxXdr,
    });

    const { data } = tx;

    return data;
}
```


# Approve Milestone

Responsible for approving the milestone through the escrow approver.

### **Headers**

<table><thead><tr><th width="366">Name</th><th>Value</th></tr></thead><tbody><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>x-api-key</td><td><code>&#x3C;token></code></td></tr></tbody></table>

### Open API

## POST /escrow/single-release/approve-milestone

>

```json
{"openapi":"3.0.0","info":{"title":"Trustless Work API","version":"1.0"},"security":[{}],"paths":{"/escrow/single-release/approve-milestone":{"post":{"operationId":"SingleReleaseController_approveMilestone","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApproveMilestone"}}}},"responses":{"201":{"description":"This endpoint returns an unsigned transaction in XDR format. This XDR is then used to sign the transaction using the “/helper/send-transaction” endpoint.","content":{"application/json":{}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized access"},"429":{"description":"Too Many Requests"},"500":{"description":"Possible errors:\n- Escrow not found\n- Only the approver can change milestone flag\n- You cannot approve a milestone that has already been approved previously\n- The milestone status cannot be empty\n- Escrow initialized without milestone\n- Invalid milestone index\n- An unexpected error occurred","content":{"application/json":{}}}},"tags":["Single Release"]}}},"components":{"schemas":{"ApproveMilestone":{"type":"object","properties":{"contractId":{"type":"string","description":"ID (address) that identifies the escrow contract"},"milestoneIndex":{"type":"string","description":"Position that identifies the milestone within the group of milestones in the escrow"},"approver":{"type":"string","description":"Address of the entity requiring the service"}},"required":["contractId","milestoneIndex","approver"]}}}}
```

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

### **What this Endpoint returns?**

This endpoint returns the transaction unsigned so that the transaction can be signed by means of a customer wallet.

### Use Example:

```typescript
import axios from "axios";

const http = axios.create({
  baseURL: "https://dev.api.trustlesswork.com",
  timeout: 10000,
  headers: {
    "Content-Type": "application/json",
    "x-api-key": your_api_key,
  },
});

export const useExample = async () => {
    // Get the signer address
    const { address } = await kit.getAddress();

    const response = await http.post(
      "/escrow/single-release/approve-milestone",
      {
        // body requested for the endpoint
      },
    ); 
    
    // Get the unsigned transaction hash
    const { unsignedTransaction } = response.data;

    // Sign the transaction by wallet
    const { signedTxXdr } = await signTransaction(unsignedTransaction, {
      address,
      networkPassphrase: WalletNetwork.TESTNET,
    });

    // Send the transaction to Stellar Network
    const tx = await http.post("/helper/send-transaction", {
      signedXdr: signedTxXdr,
    });

    const { data } = tx;

    return data;
}
```


# Change Milestone Status

Responsible for changing the milestone status of an escrow through the service provider.

### **Headers**

<table><thead><tr><th width="366">Name</th><th>Value</th></tr></thead><tbody><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>x-api-key</td><td><code>&#x3C;token></code></td></tr></tbody></table>

### Open API

## POST /escrow/single-release/change-milestone-status

>

```json
{"openapi":"3.0.0","info":{"title":"Trustless Work API","version":"1.0"},"security":[{}],"paths":{"/escrow/single-release/change-milestone-status":{"post":{"operationId":"SingleReleaseController_changeMilestoneStatus","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeMilestoneStatus"}}}},"responses":{"201":{"description":"This endpoint returns an unsigned transaction in XDR format. This XDR is then used to sign the transaction using the “/helper/send-transaction” endpoint.","content":{"application/json":{}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized access"},"429":{"description":"Too Many Requests"},"500":{"description":"Possible errors:\n- Escrow not found\n- Only the service provider can change milestone status\n- Invalid milestone index\n- Escrow initialized without milestone\n- An unexpected error occurred","content":{"application/json":{}}}},"tags":["Single Release"]}}},"components":{"schemas":{"ChangeMilestoneStatus":{"type":"object","properties":{"contractId":{"type":"string","description":"ID (address) that identifies the escrow contract"},"milestoneIndex":{"type":"string","description":"milestone within the group of milestones in the escrow"},"newEvidence":{"type":"string","description":"New value for the evidence property within the escrow milestone"},"newStatus":{"type":"string","description":"New value for the status property within the escrow milestone"},"serviceProvider":{"type":"string","description":"Address of the entity providing the service"}},"required":["contractId","milestoneIndex","newEvidence","newStatus","serviceProvider"]}}}}
```

<figure><img src="/files/8dtDWx1BfSDAaOuDQ14n" alt=""><figcaption></figcaption></figure>

### **What this Endpoint returns?**

This endpoint returns the transaction unsigned so that the transaction can be signed by means of a customer wallet.

### **Use example:**

```javascript
import axios from "axios";

const http = axios.create({
  baseURL: "https://dev.api.trustlesswork.com",
  timeout: 10000,
  headers: {
    "Content-Type": "application/json",
    "x-api-key": your_api_key,
  },
});

export const useExample = async () => {
    // Get the signer address
    const { address } = await kit.getAddress();

    const response = await http.post(
      "/escrow/single-release/change-milestone-status",
      {
        // body requested for the endpoint
      },
    ); 
    
    // Get the unsigned transaction hash
    const { unsignedTransaction } = response.data;

    // Sign the transaction by wallet
    const { signedTxXdr } = await signTransaction(unsignedTransaction, {
      address,
      networkPassphrase: WalletNetwork.TESTNET,
    });

    // Send the transaction to Stellar Network
    const tx = await http.post("/helper/send-transaction", {
      signedXdr: signedTxXdr,
    });

    const { data } = tx;

    return data;
}
```


# Release Funds

You release the escrow funds to the service provider through the approver.

### Headers

<table><thead><tr><th width="366">Name</th><th>Value</th></tr></thead><tbody><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>x-api-key</td><td><code>&#x3C;token></code></td></tr></tbody></table>

### Open API

## POST /escrow/single-release/release-funds

>

```json
{"openapi":"3.0.0","info":{"title":"Trustless Work API","version":"1.0"},"security":[{}],"paths":{"/escrow/single-release/release-funds":{"post":{"operationId":"SingleReleaseController_releaseFunds","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseFunds"}}}},"responses":{"201":{"description":"This endpoint returns an unsigned transaction in XDR format. This XDR is then used to sign the transaction using the “/helper/send-transaction” endpoint.","content":{"application/json":{}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized access"},"429":{"description":"Too Many Requests"},"500":{"description":"Possible errors:\n- The escrow funds have been released\n- This escrow is already resolved\n- Only the release signer can release the escrow earnings\n- Escrow initialized without milestone\n- The escrow must be completed to release earnings\n- Escrow has been opened for dispute resolution\n- Escrow not found\n- An unexpected error occurred","content":{"application/json":{}}}},"tags":["Single Release"]}}},"components":{"schemas":{"ReleaseFunds":{"type":"object","properties":{"contractId":{"type":"string","description":"ID (address) that identifies the escrow contract"},"releaseSigner":{"type":"string","description":"Address of the user in charge of releasing the escrow funds to the receiver"}},"required":["contractId","releaseSigner"]}}}}
```

<figure><img src="/files/1wARRlstf6pRBX9e4jQy" alt=""><figcaption></figcaption></figure>

### **What this Endpoint returns?**

This endpoint returns the transaction unsigned so that the transaction can be signed by means of a customer wallet.

### Use Example:

```typescript
import axios from "axios";

const http = axios.create({
  baseURL: "https://dev.api.trustlesswork.com",
  timeout: 10000,
  headers: {
    "Content-Type": "application/json",
    "x-api-key": your_api_key,
  },
});

export const useExample = async () => {
    // Get the signer address
    const { address } = await kit.getAddress();

    const response = await http.post(
      "/escrow/single-release/release-funds",
      {
        // body requested for the endpoint
      },
    ); 
    
    // Get the unsigned transaction hash
    const { unsignedTransaction } = response.data;

    // Sign the transaction by wallet
    const { signedTxXdr } = await signTransaction(unsignedTransaction, {
      address,
      networkPassphrase: WalletNetwork.TESTNET,
    });

    // Send the transaction to Stellar Network
    const tx = await http.post("/helper/send-transaction", {
      signedXdr: signedTxXdr,
    });

    const { data } = tx;

    return data;
}
```


# Dispute Escrow

Responsible for initiating a dispute in an escrow. Change the value of the flag “disputed” from “disputed” to true.

### **Headers**

<table><thead><tr><th width="366">Name</th><th>Value</th></tr></thead><tbody><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>x-api-key</td><td><code>&#x3C;token></code></td></tr></tbody></table>

### **Open API**

## POST /escrow/single-release/dispute-escrow

>

```json
{"openapi":"3.0.0","info":{"title":"Trustless Work API","version":"1.0"},"security":[{}],"paths":{"/escrow/single-release/dispute-escrow":{"post":{"operationId":"SingleReleaseController_disputeEscrow","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisputeEscrow"}}}},"responses":{"201":{"description":"This endpoint returns an unsigned transaction in XDR format. This XDR is then used to sign the transaction using the “/helper/send-transaction” endpoint.","content":{"application/json":{}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized access"},"429":{"description":"Too Many Requests"},"500":{"description":"Possible errors:\n- Escrow not found\n- Escrow already in dispute\n- You are not authorized to change the dispute flag\n- The dispute resolver cannot dispute the escrow\n- An unexpected error occurred","content":{"application/json":{}}}},"tags":["Single Release"]}}},"components":{"schemas":{"DisputeEscrow":{"type":"object","properties":{"contractId":{"type":"string","description":"ID (address) that identifies the escrow contract"},"signer":{"type":"string","description":"Entity that signs the transaction that deploys and initializes the escrow"}},"required":["contractId","signer"]}}}}
```

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

### **What this Endpoint returns?**

This endpoint returns the transaction unsigned so that the transaction can be signed by means of a customer wallet.

### Use Example:

```typescript
import axios from "axios";

const http = axios.create({
  baseURL: "https://dev.api.trustlesswork.com",
  timeout: 10000,
  headers: {
    "Content-Type": "application/json",
    "x-api-key": your_api_key,
  },
});

export const useExample = async () => {
    // Get the signer address
    const { address } = await kit.getAddress();

    // Execute the endpoint
    const response = await http.post(
      "/escrow/single-release/dispute-escrow",
      {
        // body requested for the endpoint
      },
    ); 
    
    // Get the unsigned transaction hash
    const { unsignedTransaction } = response.data;

    // Sign the transaction by wallet
    const { signedTxXdr } = await signTransaction(unsignedTransaction, {
      address,
      networkPassphrase: WalletNetwork.TESTNET,
    });

    // Send the transaction to Stellar Network
    const tx = await http.post("/helper/send-transaction", {
      signedXdr: signedTxXdr,
    });

    const { data } = tx;

    return data;
}
```


# Resolve Dispute

Resolves escrow disputes by distributing funds to the approver and service provider as determined by the dispute resolver.

### **Headers**

<table><thead><tr><th width="366">Name</th><th>Value</th></tr></thead><tbody><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>x-api-key</td><td><code>&#x3C;token></code></td></tr></tbody></table>

### Open API

## POST /escrow/single-release/resolve-dispute

>

```json
{"openapi":"3.0.0","info":{"title":"Trustless Work API","version":"1.0"},"security":[{}],"paths":{"/escrow/single-release/resolve-dispute":{"post":{"operationId":"SingleReleaseController_resolveDispute","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveDispute"}}}},"responses":{"201":{"description":"This endpoint returns an unsigned transaction in XDR format. This XDR is then used to sign the transaction using the “/helper/send-transaction” endpoint.","content":{"application/json":{}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized access"},"429":{"description":"Too Many Requests"},"500":{"description":"Possible errors:\n- Only the dispute resolver can execute this function\n- None of the amounts to be transferred should be less or equal than 0\n- Escrow not in dispute\n- Insufficient funds for resolution\n- The sum of distributions must equal the current escrow balance when resolving an escrow dispute\n- The total amount to be distributed cannot be equal to zero\n- Escrow not found\n- An unexpected error occurred","content":{"application/json":{}}}},"tags":["Single Release"]}}},"components":{"schemas":{"ResolveDispute":{"type":"object","properties":{"contractId":{"type":"string","description":"ID (address) that identifies the escrow contract"},"disputeResolver":{"type":"string","description":"Address of the user defined to resolve disputes in an escrow"},"distributions":{"description":"Array of distributions detailing address and amount to allocate when resolving the dispute. Amounts should sum the remaining escrow funds (post-fees).","type":"array","items":{"type":"array"}}},"required":["contractId","disputeResolver","distributions"]}}}}
```

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

### **What this Endpoint returns?**

This endpoint returns the transaction unsigned so that the transaction can be signed by means of a customer wallet.

### Use Example:

```typescript
import axios from "axios";

const http = axios.create({
  baseURL: "https://dev.api.trustlesswork.com",
  timeout: 10000,
  headers: {
    "Content-Type": "application/json",
    "x-api-key": your_api_key,
  },
});

export const useExample = async () => {
    // Get the signer address
    const { address } = await kit.getAddress();

    const response = await http.post(
      "/escrow/single-release/resolve-dispute",
      {
        // body requested for the endpoint
      },
    ); 
    
    // Get the unsigned transaction hash
    const { unsignedTransaction } = response.data;

    // Sign the transaction by wallet
    const { signedTxXdr } = await signTransaction(unsignedTransaction, {
      address,
      networkPassphrase: WalletNetwork.TESTNET,
    });

    // Send the transaction to Stellar Network
    const tx = await http.post("/helper/send-transaction", {
      signedXdr: signedTxXdr,
    });

    const { data } = tx;

    return data;
}
```


# Update Escrow

This endpoint allows you to change the properties of an escrow as long as a series of requirements are met, which will be mentioned in this section.

### Requirements to use:

1. Only the entity with the platform role has permissions to execute this endpoint
2. If an escrow has funds, the only thing the platform can do is add more milestones. The other properties cannot be modified under any circumstances.

### Headers

<table><thead><tr><th width="366">Name</th><th>Value</th></tr></thead><tbody><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>x-api-key</td><td><code>&#x3C;token></code></td></tr></tbody></table>

### Roles:

| Name            | Type   | Description                                                                          |
| --------------- | ------ | ------------------------------------------------------------------------------------ |
| approver        | string | Address of the entity requiring the service.                                         |
| serviceProvider | string | Address of the entity providing the service.                                         |
| platformAddress | string | Address of the entity that owns the escrow                                           |
| releaseSigner   | string | Address of the user in charge of releasing the escrow funds to the service provider. |
| disputeResolver | string | Address in charge of resolving disputes within the escrow.                           |
| receiver        | string | Address where escrow proceeds will be sent to                                        |

### Milestone:

| Name        | Type    | Description                                                            |
| ----------- | ------- | ---------------------------------------------------------------------- |
| description | string  | Text describing the function of the milestone.                         |
| status      | string  | Milestone status. Ex: Approved, In dispute, etc...                     |
| approved    | boolean | Flag indicating whether a milestone has been approved by the approver. |

### Flags

| Name     | Type    | Description                                                       |
| -------- | ------- | ----------------------------------------------------------------- |
| disputed | boolean | Flag indicating that an escrow is in dispute.                     |
| released | boolean | Flag indicating that escrow funds have already been released.     |
| resolved | boolean | Flag indicating that a disputed escrow has already been resolved. |

### Trustline

| Name    | Type   | Description                                                                |
| ------- | ------ | -------------------------------------------------------------------------- |
| address | string | Public address establishing permission to accept and use a specific token. |

### Open API

## PUT /escrow/single-release/update-escrow

>

```json
{"openapi":"3.0.0","info":{"title":"Trustless Work API","version":"1.0"},"security":[{}],"paths":{"/escrow/single-release/update-escrow":{"put":{"operationId":"SingleReleaseController_updateEscrow","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSingleReleaseEscrow"}}}},"responses":{"200":{"description":"This endpoint returns an unsigned transaction in XDR format. This XDR is then used to sign the transaction using the “/helper/send-transaction” endpoint.","content":{"application/json":{}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized access"},"429":{"description":"Too Many Requests"},"500":{"description":"Possible errors:\n- Escrow not found\n- The platform fee cannot exceed 99%\n- Amount cannot be equal to or less than zero\n- Escrow initialized without milestone\n- Cannot define more than 50 milestones in an escrow\n- Only the platform address should be able to execute this function\n- The platform address of the escrow cannot be changed\n- Escrow has been opened for dispute resolution\n- All flags (approved, disputed, released) must be false in order to execute this function\n- The provided escrow properties do not match the stored escrow\n- You can't change the escrow properties after the milestone is approved\n- An unexpected error occurred","content":{"application/json":{}}}},"tags":["Single Release"]}}},"components":{"schemas":{"UpdateSingleReleaseEscrow":{"type":"object","properties":{"signer":{"type":"string","description":"Entity that signs the transaction that deploys and initializes the escrow"},"contractId":{"type":"string","description":"ID (address) that identifies the escrow contract"},"escrow":{"description":"Escrow data to update","allOf":[{"$ref":"#/components/schemas/EscrowData"}]}},"required":["signer","contractId","escrow"]},"EscrowData":{"type":"object","properties":{"engagementId":{"type":"string","description":"Unique identifier for the escrow"},"title":{"type":"string","description":"Name of the escrow"},"description":{"type":"string","description":"Text describing the function of the escrow"},"roles":{"description":"Roles that make up the escrow structure","type":"array","items":{"type":"object"}},"amount":{"type":"number","description":"Amount to be transferred upon completion of escrow milestones"},"platformFee":{"type":"number","description":"Commission that the platform will receive when the escrow is completed"},"milestones":{"description":"Objectives to be completed to define the escrow as completed","type":"array","items":{"type":"string"}},"flags":{"description":"Flags validating certain escrow life states","type":"array","items":{"type":"object"}},"isActive":{"type":"boolean","description":"Flag indicating whether the escrow is active or not at the database level. Makes only a logical deletion, the escrow will continue to function at the blockchain level."},"receiverMemo":{"type":"number","description":"Field used to identify the recipient's address in transactions through an intermediary account. This value is included as a memo in the transaction and allows the funds to be correctly routed to the wallet of the specified recipient"},"trustline":{"description":"Information on the trustline that will manage the movement of funds in escrow","type":"array","items":{"type":"object"}}},"required":["engagementId","title","description","roles","amount","platformFee","milestones","flags","isActive","receiverMemo","trustline"]}}}}
```

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

### **What this Endpoint returns?**

This endpoint returns the transaction unsigned so that the transaction can be signed by means of a customer wallet.

### Use Example:

```typescript
import axios from "axios";

const http = axios.create({
  baseURL: "https://dev.api.trustlesswork.com",
  timeout: 10000,
  headers: {
    "Content-Type": "application/json",
    "x-api-key": your_api_key,
  },
});

export const useExample = async () => {
    // Get the signer address
    const { address } = await kit.getAddress();

    const response = await http.put(
      "/escrow/single-release/update-escrow",
      {
        // body requested for the endpoint
      },
    ); 
    
    // Get the unsigned transaction hash
    const { unsignedTransaction } = response.data;

    // Sign the transaction by wallet
    const { signedTxXdr } = await signTransaction(unsignedTransaction, {
      address,
      networkPassphrase: WalletNetwork.TESTNET,
    });

    // Send the transaction to Stellar Network
    const tx = await http.post("/helper/send-transaction", {
      signedXdr: signedTxXdr,
    });

    const { data } = tx;

    return data;
}
```


# Multi Release Escrow

A Multi-Release Contract is an escrow agreement on the Stellar blockchain that divides the total payment of a project into multiple deliveries (“milestones”). Each milestone is released only upon verification of its completion, ensuring that funds remain secure until the associated work is validated.

**Key Components**

* **Initial Fund Lockup**: Upon contract initiation, the total of all milestone amounts plus the platform fee (“platformFee”) is deposited into an escrow account.
* **Milestones**: Each stage includes a description, a specific amount, and status flags (`approved`, `dispute`, `released`, `resolved`).
* **Primary Roles**:
  * **Service Provider**: Delivers the deliverable corresponding to each milestone.
  * **Approver**: Verifies and approves a milestone before authorizing the release of funds.
  * **Dispute Resolver**: Intervenes in case of disagreement and decides whether to release or refund the locked amount.
  * **Receiver**: The final recipient of the funds if different from the Service Provider.

**Brief Workflow**

1. The Service Provider completes a milestone and requests approval.
2. The Approver reviews the deliverable; if approved, they sign a transaction that releases only the amount allocated to that milestone (minus the platform and Trustless Work fee).
3. The Stellar network executes the transaction and transfers the payment to the Service Provider or the configured Receiver.
4. If a dispute arises, the Dispute Resolver evaluates the evidence and, upon signing their decision, marks the milestone as `resolved` to release or refund the corresponding funds.

This model protects all parties: the client knows that funds are available but cannot be released without validation, and the Service Provider receives payment for each verified delivery—leveraging Stellar’s transparency and immutability.


# Deploy

Deploy the escrow contract and define the escrow properties.

### Headers

<table><thead><tr><th width="366">Name</th><th>Value</th></tr></thead><tbody><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>x-api-key</td><td><code>&#x3C;token></code></td></tr></tbody></table>

### Milestone

| Name        | Type                             | Description                                                           |
| ----------- | -------------------------------- | --------------------------------------------------------------------- |
| description | string                           | Text describing the function of the milestone                         |
| status      | string (Default value: "peding") | Milestone status. Ex: Approved, In dispute, etc...                    |
| approved    | boolean (Default value: false)   | Flag indicating whether a milestone has been approved by the approver |
| amount      | string                           | Amount of the milestone                                               |
| receiver    | string                           | Address where escrow proceeds will be sent to                         |

### Roles:

| Name             | Type   | Description                                                                          |
| ---------------- | ------ | ------------------------------------------------------------------------------------ |
| approver         | string | Address of the entity requiring the service.                                         |
| serviceProvider  | string | Address of the entity providing the service.                                         |
| plataformAddress | string | Address of the entity that owns the escrow                                           |
| releaseSigner    | string | Address of the user in charge of releasing the escrow funds to the service provider. |
| disputeResolver  | string | Address in charge of resolving disputes within the escrow.                           |

### Trustline:

| Name    | Type   | Description                                                                            |
| ------- | ------ | -------------------------------------------------------------------------------------- |
| address | string | Public address establishing permission to accept and use a specific token.             |
| symbol  | string | Official abbreviation representing the token in wallets, exchanges, and documentation. |

### Initialize Escrow

## POST /deployer/multi-release

>

```json
{"openapi":"3.0.0","info":{"title":"Trustless Work API","version":"1.0"},"security":[{}],"paths":{"/deployer/multi-release":{"post":{"operationId":"DeployerController_deployMultiReleaseContract","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MultiReleaseContract"}}}},"responses":{"201":{"description":"This endpoint returns an unsigned transaction in XDR format. This XDR is then used to sign the transaction using the “/helper/send-transaction” endpoint.","content":{"application/json":{}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized access"},"429":{"description":"Too Many Requests"},"500":{"description":"Possible errors:\n- Escrow already initialized\n- The platform fee cannot exceed 99%\n- Escrow initialized without milestone\n- Cannot define more than 50 milestones in an escrow\n- Amount cannot be zero\n- All flags (approved, disputed, released) must be false in order to execute this function\n- An unexpected error occurred","content":{"application/json":{}}}},"tags":["Deployer"]}}},"components":{"schemas":{"MultiReleaseContract":{"type":"object","properties":{"signer":{"type":"string","description":"Entity that signs the transaction that deploys and initializes the escrow"},"engagementId":{"type":"string","description":"Unique identifier for the escrow"},"title":{"type":"string","description":"Name of the escrow"},"description":{"type":"string","description":"Text describing the function of the escrow"},"roles":{"description":"Roles that make up the escrow structure","type":"array","items":{"type":"object"}},"platformFee":{"type":"number","description":"Commission that the platform will receive when the escrow is completed"},"milestones":{"description":"Objectives to be completed to define the escrow as completed. (In this case it is not necessary to send the properties “approvedFlag” and “status” inside the objects of these milestones)","type":"array","items":{"type":"object"}},"trustline":{"description":"Information on the trustline that will manage the movement of funds in escrow","type":"array","items":{"type":"object"}}},"required":["signer","engagementId","title","description","roles","platformFee","milestones","trustline"]}}}}
```

<figure><img src="/files/84QhVcgwQJqytVjwyfsT" alt=""><figcaption></figcaption></figure>

### **What this Endpoint returns?**

This endpoint returns the transaction unsigned so that the transaction can be signed by means of a customer wallet.

### Use Example:

<pre class="language-typescript"><code class="lang-typescript">import axios from "axios";

const http = axios.create({
  baseURL: "https://dev.api.trustlesswork.com",
  timeout: 10000,
  headers: {
    "Content-Type": "application/json",
    "x-api-key": your_api_key,
  },
});

export const useExample = async () => {
    // Get the signer address
    const { address } = await kit.getAddress();

    // Execute the endpoint
<strong>    const response = await http.post(
</strong>      "/deployer/multi-release",
      {
        // body requested for the endpoint
      },
    );
    
    // Get the unsigned transaction hash
    const { unsignedTransaction } = response.data;

    // Sign the transaction by wallet
    const { signedTxXdr } = await signTransaction(unsignedTransaction, {
      address,
      networkPassphrase: WalletNetwork.TESTNET,
    });

    // Send the transaction to Stellar Network
    const tx = await http.post("/helper/send-transaction", {
      signedXdr: signedTxXdr,
    });

    const { data } = tx;

    return data; 
}
</code></pre>


# Fund Escrow

Allows users to deposit funds into an existing escrow contract, securing them until the agreed conditions are met.

### **Headers**

<table><thead><tr><th width="366">Name</th><th>Value</th></tr></thead><tbody><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>x-api-key</td><td><code>&#x3C;token></code></td></tr></tbody></table>

### **Open API**

## POST /escrow/multi-release/fund-escrow

>

```json
{"openapi":"3.0.0","info":{"title":"Trustless Work API","version":"1.0"},"security":[{}],"paths":{"/escrow/multi-release/fund-escrow":{"post":{"operationId":"MultiReleaseController_fundEscrow","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FundEscrow"}}}},"responses":{"201":{"description":"This endpoint returns an unsigned transaction in XDR format. This XDR is then used to sign the transaction using the “/helper/send-transaction” endpoint.","content":{"application/json":{}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized access"},"429":{"description":"Too Many Requests"},"500":{"description":"Possible errors:\n- Amount cannot be equal to or less than zero\n- The provided escrow properties do not match the stored escrow\n- An unexpected error occurred","content":{"application/json":{}}}},"tags":["Multi Release"]}}},"components":{"schemas":{"FundEscrow":{"type":"object","properties":{"contractId":{"type":"string","description":"ID (address) that identifies the escrow contract"},"signer":{"type":"string","description":"Entity that signs the transaction that deploys and initializes the escrow"},"amount":{"type":"number","description":"Amount to transfer to the escrow contract"}},"required":["contractId","signer","amount"]}}}}
```

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

### **What this Endpoint returns?**

This endpoint returns the transaction unsigned so that the transaction can be signed by means of a customer wallet.

### Use Example:

```typescript
import axios from "axios";

const http = axios.create({
  baseURL: "https://dev.api.trustlesswork.com",
  timeout: 10000,
  headers: {
    "Content-Type": "application/json",
    "x-api-key": your_api_key,
  },
});

export const useExample = async () => {
    // Get the signer address
    const { address } = await kit.getAddress();

    const response = await http.post(
      "/escrow/multi-release/fund-escrow",
      {
        // body requested for the endpoint
      },
    ); 
    
    // Get the unsigned transaction hash
    const { unsignedTransaction } = response.data;

    // Sign the transaction by wallet
    const { signedTxXdr } = await signTransaction(unsignedTransaction, {
      address,
      networkPassphrase: WalletNetwork.TESTNET,
    });

    // Send the transaction to Stellar Network
    const tx = await http.post("/helper/send-transaction", {
      signedXdr: signedTxXdr,
    });

    const { data } = tx;

    return data;
}
```


# Approve Milestone

Responsible for modifying the "flag" property of a specific milestone in the escrow to approve that milestone.

### **Headers**

<table><thead><tr><th width="366">Name</th><th>Value</th></tr></thead><tbody><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>x-api-key</td><td><code>&#x3C;token></code></td></tr></tbody></table>

### Open API

## POST /escrow/multi-release/approve-milestone

>

```json
{"openapi":"3.0.0","info":{"title":"Trustless Work API","version":"1.0"},"security":[{}],"paths":{"/escrow/multi-release/approve-milestone":{"post":{"operationId":"MultiReleaseController_approveMilestone","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApproveMilestone"}}}},"responses":{"201":{"description":"This endpoint returns an unsigned transaction in XDR format. This XDR is then used to sign the transaction using the “/helper/send-transaction” endpoint.","content":{"application/json":{}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized access"},"429":{"description":"Too Many Requests"},"500":{"description":"Possible errors:\n- Escrow not found\n- Only the approver can change milestone flag\n- You cannot approve a milestone that has already been approved previously\n- The milestone status cannot be empty\n- Escrow initialized without milestone\n- Invalid milestone index\n- An unexpected error occurred","content":{"application/json":{}}}},"tags":["Multi Release"]}}},"components":{"schemas":{"ApproveMilestone":{"type":"object","properties":{"contractId":{"type":"string","description":"ID (address) that identifies the escrow contract"},"milestoneIndex":{"type":"string","description":"Position that identifies the milestone within the group of milestones in the escrow"},"approver":{"type":"string","description":"Address of the entity requiring the service"}},"required":["contractId","milestoneIndex","approver"]}}}}
```

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

### **What this Endpoint returns?**

This endpoint returns the transaction unsigned so that the transaction can be signed by means of a customer wallet.

### Use Example:

```typescript
import axios from "axios";

const http = axios.create({
  baseURL: "https://dev.api.trustlesswork.com",
  timeout: 10000,
  headers: {
    "Content-Type": "application/json",
    "x-api-key": your_api_key,
  },
});

export const useExample = async () => {
    // Get the signer address
    const { address } = await kit.getAddress();

    const response = await http.post(
      "/escrow/multi-release/approve-milestone",
      {
        // body requested for the endpoint
      },
    ); 
    
    // Get the unsigned transaction hash
    const { unsignedTransaction } = response.data;

    // Sign the transaction by wallet
    const { signedTxXdr } = await signTransaction(unsignedTransaction, {
      address,
      networkPassphrase: WalletNetwork.TESTNET,
    });

    // Send the transaction to Stellar Network
    const tx = await http.post("/helper/send-transaction", {
      signedXdr: signedTxXdr,
    });

    const { data } = tx;

    return data;
}
```


# Change Milestone Status

Responsible for modifying the "status" property of a specific milestone in the escrow.

### **Headers**

<table><thead><tr><th width="366">Name</th><th>Value</th></tr></thead><tbody><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>x-api-key</td><td><code>&#x3C;token></code></td></tr></tbody></table>

### Open API

## POST /escrow/multi-release/change-milestone-status

>

```json
{"openapi":"3.0.0","info":{"title":"Trustless Work API","version":"1.0"},"security":[{}],"paths":{"/escrow/multi-release/change-milestone-status":{"post":{"operationId":"MultiReleaseController_changeMilestoneStatus","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeMilestoneStatus"}}}},"responses":{"201":{"description":"This endpoint returns an unsigned transaction in XDR format. This XDR is then used to sign the transaction using the “/helper/send-transaction” endpoint.","content":{"application/json":{}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized access"},"429":{"description":"Too Many Requests"},"500":{"description":"Possible errors:\n- Escrow not found\n- Only the service provider can change milestone status\n- Invalid milestone index\n- Escrow initialized without milestone\n- An unexpected error occurred","content":{"application/json":{}}}},"tags":["Multi Release"]}}},"components":{"schemas":{"ChangeMilestoneStatus":{"type":"object","properties":{"contractId":{"type":"string","description":"ID (address) that identifies the escrow contract"},"milestoneIndex":{"type":"string","description":"milestone within the group of milestones in the escrow"},"newEvidence":{"type":"string","description":"New value for the evidence property within the escrow milestone"},"newStatus":{"type":"string","description":"New value for the status property within the escrow milestone"},"serviceProvider":{"type":"string","description":"Address of the entity providing the service"}},"required":["contractId","milestoneIndex","newEvidence","newStatus","serviceProvider"]}}}}
```

<figure><img src="/files/3TLtVTjt2lS1CxzGr8oD" alt=""><figcaption></figcaption></figure>

### **What this Endpoint returns?**

This endpoint returns the transaction unsigned so that the transaction can be signed by means of a customer wallet.

### **Use example:**

```javascript
import axios from "axios";

const http = axios.create({
  baseURL: "https://dev.api.trustlesswork.com",
  timeout: 10000,
  headers: {
    "Content-Type": "application/json",
    "x-api-key": your_api_key,
  },
});

export const useExample = async () => {
    // Get the signer address
    const { address } = await kit.getAddress();

    const response = await http.post(
      "/escrow/multi-release/change-milestone-status",
      {
        // body requested for the endpoint
      },
    ); 
    
    // Get the unsigned transaction hash
    const { unsignedTransaction } = response.data;

    // Sign the transaction by wallet
    const { signedTxXdr } = await signTransaction(unsignedTransaction, {
      address,
      networkPassphrase: WalletNetwork.TESTNET,
    });

    // Send the transaction to Stellar Network
    const tx = await http.post("/helper/send-transaction", {
      signedXdr: signedTxXdr,
    });

    const { data } = tx;

    return data;
}
```


# Release Milestone Funds

You release the milestone escrow funds to the service provider through the approver.

### Headers

<table><thead><tr><th width="366">Name</th><th>Value</th></tr></thead><tbody><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>x-api-key</td><td><code>&#x3C;token></code></td></tr></tbody></table>

### Open API

## POST /escrow/multi-release/release-milestone-funds

>

```json
{"openapi":"3.0.0","info":{"title":"Trustless Work API","version":"1.0"},"security":[{}],"paths":{"/escrow/multi-release/release-milestone-funds":{"post":{"operationId":"MultiReleaseController_releaseMilestonePayment","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseMilestoneFunds"}}}},"responses":{"201":{"description":"This endpoint returns an unsigned transaction in XDR format. This XDR is then used to sign the transaction using the “/helper/send-transaction” endpoint.","content":{"application/json":{}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized access"},"429":{"description":"Too Many Requests"},"500":{"description":"Possible errors:\n- This milestone is already released\n- This escrow is already resolved\n- Only the release signer can release the escrow funds\n- Escrow initialized without milestone\n- The milestone must be completed to release funds\n- Milestone has been opened for dispute resolution\n- Invalid milestone index\n- The escrow balance must be equal to the amount of earnings defined for the escrow\n- Escrow not found\n- An unexpected error occurred","content":{"application/json":{}}}},"tags":["Multi Release"]}}},"components":{"schemas":{"ReleaseMilestoneFunds":{"type":"object","properties":{"contractId":{"type":"string","description":"ID (address) that identifies the escrow contract"},"releaseSigner":{"type":"string","description":"Address of the user in charge of releasing the escrow funds to the receiver"},"milestoneIndex":{"type":"string","description":"Position that identifies the milestone within the group of milestones in the escrow"}},"required":["contractId","releaseSigner","milestoneIndex"]}}}}
```

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

### **What this Endpoint returns?**

This endpoint returns the transaction unsigned so that the transaction can be signed by means of a customer wallet.

### Use Example:

```typescript
import axios from "axios";

const http = axios.create({
  baseURL: "https://dev.api.trustlesswork.com",
  timeout: 10000,
  headers: {
    "Content-Type": "application/json",
    "x-api-key": your_api_key,
  },
});

export const useExample = async () => {
    // Get the signer address
    const { address } = await kit.getAddress();

    const response = await http.post(
      "/escrow/multi-release/release-milestone-funds",
      {
        // body requested for the endpoint
      },
    ); 
    
    // Get the unsigned transaction hash
    const { unsignedTransaction } = response.data;

    // Sign the transaction by wallet
    const { signedTxXdr } = await signTransaction(unsignedTransaction, {
      address,
      networkPassphrase: WalletNetwork.TESTNET,
    });

    // Send the transaction to Stellar Network
    const tx = await http.post("/helper/send-transaction", {
      signedXdr: signedTxXdr,
    });

    const { data } = tx;

    return data;
}
```


# Withdraw Remaining Funds

This function is used to withdraw funds that are stuck in escrow and cannot be withdrawn due to the way multi-release escrow works, since disputes in this case are handled at the milestone level.

In single-release escrow accounts, this endpoint is not necessary because disputes are handled at the escrow account level, so if there is any remaining balance in the contract, a dispute is opened and the remaining balance is withdrawn.

### Headers

<table><thead><tr><th width="366">Name</th><th>Value</th></tr></thead><tbody><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>x-api-key</td><td><code>&#x3C;token></code></td></tr></tbody></table>

### Open API

## POST /escrow/multi-release/withdraw-remaining-funds

>

```json
{"openapi":"3.0.0","info":{"title":"Trustless Work API","version":"1.0"},"security":[{}],"paths":{"/escrow/multi-release/withdraw-remaining-funds":{"post":{"operationId":"MultiReleaseController_withdrawRemainingFunds","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WithdrawRemainingFunds"}}}},"responses":{"201":{"description":"This endpoint returns an unsigned transaction in XDR format. This XDR is then used to sign the transaction using the “/helper/send-transaction” endpoint.","content":{"application/json":{}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized access"},"429":{"description":"Too Many Requests"},"500":{"description":"Possible errors:\n- Escrow not found\n- None of the amounts to be transferred should be less or equal than 0\n- Only the dispute resolver can execute this function\n- All milestones must be released or dispute-resolved before withdrawing remaining funds\n- The total amount to be transferred cannot be zero\n- Insufficient funds for resolution\n- An unexpected error occurred","content":{"application/json":{}}}},"tags":["Multi Release"]}}},"components":{"schemas":{"WithdrawRemainingFunds":{"type":"object","properties":{"contractId":{"type":"string","description":"ID (address) that identifies the escrow contract"},"disputeResolver":{"type":"string","description":"Address of the user defined to resolve disputes in an escrow"},"distributions":{"description":"Array of distributions detailing address and amount to allocate when withdrawing the remaining funds after resolution or completion. Amounts should sum the remaining escrow balance (post-fees).","type":"array","items":{"type":"array"}}},"required":["contractId","disputeResolver","distributions"]}}}}
```

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

### **What this Endpoint returns?**

This endpoint returns the transaction unsigned so that the transaction can be signed by means of a customer wallet.

### Use Example:

```typescript
import axios from "axios";

const http = axios.create({
  baseURL: "https://dev.api.trustlesswork.com",
  timeout: 10000,
  headers: {
    "Content-Type": "application/json",
    "x-api-key": your_api_key,
  },
});

export const useExample = async () => {
    // Get the signer address
    const { address } = await kit.getAddress();

    const response = await http.post(
      "/escrow/multi-release/withdraw-remaining-funds",
      {
        // body requested for the endpoint
      },
    ); 
    
    // Get the unsigned transaction hash
    const { unsignedTransaction } = response.data;

    // Sign the transaction by wallet
    const { signedTxXdr } = await signTransaction(unsignedTransaction, {
      address,
      networkPassphrase: WalletNetwork.TESTNET,
    });

    // Send the transaction to Stellar Network
    const tx = await http.post("/helper/send-transaction", {
      signedXdr: signedTxXdr,
    });

    const { data } = tx;

    return data;
}
```


# Dispute Milestone

Responsible for setting the milestone in dispute state. Changes the value of the milestone's "flags.disputed" property to true.

### **Headers**

<table><thead><tr><th width="366">Name</th><th>Value</th></tr></thead><tbody><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>x-api-key</td><td><code>&#x3C;token></code></td></tr></tbody></table>

### **Open API**

## POST /escrow/multi-release/dispute-milestone

>

```json
{"openapi":"3.0.0","info":{"title":"Trustless Work API","version":"1.0"},"security":[{}],"paths":{"/escrow/multi-release/dispute-milestone":{"post":{"operationId":"MultiReleaseController_disputeMilestone","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisputeMilestone"}}}},"responses":{"201":{"description":"This endpoint returns an unsigned transaction in XDR format. This XDR is then used to sign the transaction using the “/helper/send-transaction” endpoint.","content":{"application/json":{}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized access"},"429":{"description":"Too Many Requests"},"500":{"description":"Possible errors:\n- Escrow not found\n- Escrow initialized without milestone\n- Invalid milestone index\n- This milestone is already released\n- This milestone is already resolved\n- Milestone already in dispute\n- You are not authorized to change the dispute flag\n- The dispute resolver cannot be the one to raise a dispute on a milestone\n- An unexpected error occurred","content":{"application/json":{}}}},"tags":["Multi Release"]}}},"components":{"schemas":{"DisputeMilestone":{"type":"object","properties":{"contractId":{"type":"string","description":"ID (address) that identifies the escrow contract"},"milestoneIndex":{"type":"string","description":"Position that identifies the milestone within the group of milestones in the escrow"},"signer":{"type":"string","description":"Entity that signs the transaction that deploys and initializes the escrow"}},"required":["contractId","milestoneIndex","signer"]}}}}
```

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

### **What this Endpoint returns?**

This endpoint returns the transaction unsigned so that the transaction can be signed by means of a customer wallet.

### Use Example:

```typescript
import axios from "axios";

const http = axios.create({
  baseURL: "https://dev.api.trustlesswork.com",
  timeout: 10000,
  headers: {
    "Content-Type": "application/json",
    "x-api-key": your_api_key,
  },
});

export const useExample = async () => {
    // Get the signer address
    const { address } = await kit.getAddress();

    // Execute the endpoint
    const response = await http.post(
      "/escrow/multi-release/dispute-milestone",
      {
        // body requested for the endpoint
      },
    ); 
    
    // Get the unsigned transaction hash
    const { unsignedTransaction } = response.data;

    // Sign the transaction by wallet
    const { signedTxXdr } = await signTransaction(unsignedTransaction, {
      address,
      networkPassphrase: WalletNetwork.TESTNET,
    });

    // Send the transaction to Stellar Network
    const tx = await http.post("/helper/send-transaction", {
      signedXdr: signedTxXdr,
    });

    const { data } = tx;

    return data;
}
```


# Resolve Milestone Dispute

Resolves escrow milestone disputes by distributing funds to the approver and service provider as determined by the dispute resolver.

### **Headers**

<table><thead><tr><th width="366">Name</th><th>Value</th></tr></thead><tbody><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>x-api-key</td><td><code>&#x3C;token></code></td></tr></tbody></table>

### Open API

## POST /escrow/multi-release/resolve-milestone-dispute

>

```json
{"openapi":"3.0.0","info":{"title":"Trustless Work API","version":"1.0"},"security":[{}],"paths":{"/escrow/multi-release/resolve-milestone-dispute":{"post":{"operationId":"MultiReleaseController_resolveMilestoneDispute","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveMilestoneDispute"}}}},"responses":{"201":{"description":"This endpoint returns an unsigned transaction in XDR format. This XDR is then used to sign the transaction using the “/helper/send-transaction” endpoint.","content":{"application/json":{}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized access"},"429":{"description":"Too Many Requests"},"500":{"description":"Possible errors:\n- Escrow not found\n- Invalid milestone index\n- None of the amounts to be transferred should be less or equal than 0\n- Only the dispute resolver can execute this function\n- This milestone is already released\n- This milestone is already resolved\n- Milestone not in dispute\n- The total funds to resolve the dispute must not exceed the amount defined for this milestone\n- Insufficient funds for resolution\n- The total amount to be transferred cannot be zero\n- An unexpected error occurred","content":{"application/json":{}}}},"tags":["Multi Release"]}}},"components":{"schemas":{"ResolveMilestoneDispute":{"type":"object","properties":{"contractId":{"type":"string","description":"ID (address) that identifies the escrow contract"},"disputeResolver":{"type":"string","description":"Address of the user defined to resolve disputes in an escrow"},"milestoneIndex":{"type":"string","description":"Position that identifies the milestone within the group of milestones in the escrow"},"distributions":{"description":"Array of distributions detailing address and amount to allocate when resolving the milestone dispute. Amounts should sum the remaining milestone funds (post-fees).","type":"array","items":{"type":"array"}}},"required":["contractId","disputeResolver","milestoneIndex","distributions"]}}}}
```

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

### **What this Endpoint returns?**

This endpoint returns the transaction unsigned so that the transaction can be signed by means of a customer wallet.

### Use Example:

```typescript
import axios from "axios";

const http = axios.create({
  baseURL: "https://dev.api.trustlesswork.com",
  timeout: 10000,
  headers: {
    "Content-Type": "application/json",
    "x-api-key": your_api_key,
  },
});

export const useExample = async () => {
    // Get the signer address
    const { address } = await kit.getAddress();

    const response = await http.post(
      "/escrow/multi-release/resolve-milestone-dispute",
      {
        // body requested for the endpoint
      },
    ); 
    
    // Get the unsigned transaction hash
    const { unsignedTransaction } = response.data;

    // Sign the transaction by wallet
    const { signedTxXdr } = await signTransaction(unsignedTransaction, {
      address,
      networkPassphrase: WalletNetwork.TESTNET,
    });

    // Send the transaction to Stellar Network
    const tx = await http.post("/helper/send-transaction", {
      signedXdr: signedTxXdr,
    });

    const { data } = tx;

    return data;
}
```


# Update Escrow

This endpoint allows you to change the properties of an escrow as long as a series of requirements are met, which will be mentioned in this section.

### Requirements to use:

1. Only the entity with the platform role has permissions to execute this endpoint
2. If an escrow has funds, the only thing the platform can do is add more milestones. The other properties cannot be modified under any circumstances.

### Headers

<table><thead><tr><th width="366">Name</th><th>Value</th></tr></thead><tbody><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>x-api-key</td><td><code>&#x3C;token></code></td></tr></tbody></table>

### Roles:

| Name            | Type   | Description                                                                          |
| --------------- | ------ | ------------------------------------------------------------------------------------ |
| approver        | string | Address of the entity requiring the service.                                         |
| serviceProvider | string | Address of the entity providing the service.                                         |
| platformAddress | string | Address of the entity that owns the escrow                                           |
| releaseSigner   | string | Address of the user in charge of releasing the escrow funds to the service provider. |
| disputeResolver | string | Address in charge of resolving disputes within the escrow.                           |
| receiver        | string | Address where escrow proceeds will be sent to                                        |

### Milestone:

| Name        | Type    | Description                                        |
| ----------- | ------- | -------------------------------------------------- |
| description | string  | Text describing the function of the milestone.     |
| status      | string  | Milestone status. Ex: Approved, In dispute, etc... |
| amount      | boolean | Amount of the milestone                            |

### Trustline

| Name    | Type   | Description                                                                |
| ------- | ------ | -------------------------------------------------------------------------- |
| address | string | Public address establishing permission to accept and use a specific token. |

### Open API

## PUT /escrow/multi-release/update-escrow

>

```json
{"openapi":"3.0.0","info":{"title":"Trustless Work API","version":"1.0"},"security":[{}],"paths":{"/escrow/multi-release/update-escrow":{"put":{"operationId":"MultiReleaseController_updateEscrow","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMultiReleaseEscrow"}}}},"responses":{"200":{"description":"This endpoint returns an unsigned transaction in XDR format. This XDR is then used to sign the transaction using the “/helper/send-transaction” endpoint.","content":{"application/json":{}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized access"},"429":{"description":"Too Many Requests"},"500":{"description":"Possible errors:\n- The platform fee cannot exceed 99%\n- Escrow initialized without milestone\n- Cannot define more than 50 milestones in an escrow\n- Amount cannot be zero\n- Escrow not found\n- Only the platform address should be able to execute this function\n- The platform address of the escrow cannot be changed\n- The provided escrow properties do not match the stored escrow\n- All flags (approved, disputed, released) must be false in order to execute this function","content":{"application/json":{}}}},"tags":["Multi Release"]}}},"components":{"schemas":{"UpdateMultiReleaseEscrow":{"type":"object","properties":{"signer":{"type":"string","description":"Entity that signs the transaction that deploys and initializes the escrow"},"contractId":{"type":"string","description":"ID (address) that identifies the escrow contract"},"escrow":{"description":"Escrow data to update","allOf":[{"$ref":"#/components/schemas/EscrowData"}]}},"required":["signer","contractId","escrow"]},"EscrowData":{"type":"object","properties":{"engagementId":{"type":"string","description":"Unique identifier for the escrow"},"title":{"type":"string","description":"Name of the escrow"},"description":{"type":"string","description":"Text describing the function of the escrow"},"roles":{"description":"Roles that make up the escrow structure","type":"array","items":{"type":"object"}},"amount":{"type":"number","description":"Amount to be transferred upon completion of escrow milestones"},"platformFee":{"type":"number","description":"Commission that the platform will receive when the escrow is completed"},"milestones":{"description":"Objectives to be completed to define the escrow as completed","type":"array","items":{"type":"string"}},"flags":{"description":"Flags validating certain escrow life states","type":"array","items":{"type":"object"}},"isActive":{"type":"boolean","description":"Flag indicating whether the escrow is active or not at the database level. Makes only a logical deletion, the escrow will continue to function at the blockchain level."},"receiverMemo":{"type":"number","description":"Field used to identify the recipient's address in transactions through an intermediary account. This value is included as a memo in the transaction and allows the funds to be correctly routed to the wallet of the specified recipient"},"trustline":{"description":"Information on the trustline that will manage the movement of funds in escrow","type":"array","items":{"type":"object"}}},"required":["engagementId","title","description","roles","amount","platformFee","milestones","flags","isActive","receiverMemo","trustline"]}}}}
```

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

### **What this Endpoint returns?**

This endpoint returns the transaction unsigned so that the transaction can be signed by means of a customer wallet.

### Use Example:

```typescript
import axios from "axios";

const http = axios.create({
  baseURL: "https://dev.api.trustlesswork.com",
  timeout: 10000,
  headers: {
    "Content-Type": "application/json",
    "x-api-key": your_api_key,
  },
});

export const useExample = async () => {
    // Get the signer address
    const { address } = await kit.getAddress();

    const response = await http.put(
      "/escrow/multi-release/update-escrow",
      {
        // body requested for the endpoint
      },
    ); 
    
    // Get the unsigned transaction hash
    const { unsignedTransaction } = response.data;

    // Sign the transaction by wallet
    const { signedTxXdr } = await signTransaction(unsignedTransaction, {
      address,
      networkPassphrase: WalletNetwork.TESTNET,
    });

    // Send the transaction to Stellar Network
    const tx = await http.post("/helper/send-transaction", {
      signedXdr: signedTxXdr,
    });

    const { data } = tx;

    return data;
}
```


# Helpers

These endpoints provide a way to receive tokens through Trustline and send any transactions to the Stellar Blockchain.

### Introduction

Helper endpoints are designed to provide additional functionalities that complement the main features of an API. They often include utility functions that streamline common requests, simplify data manipulation, or enhance overall user experience.

#### Helper Endpoint Overview

Helper endpoints offer several benefits that enhance both development efficiency and user satisfaction.&#x20;

* **Set Trustline:** Allows the user to interact with some tokens.
* **Send Transaction:** Send the transaction to Stellar Network with the signed hash.
* **Get Multiple Escrow Balance:** This endpoint allows users to retrieve the balances of multiple escrow accounts simultaneously.&#x20;

These endpoints ensure secure transactions by leveraging Stellar's infrastructure, guaranteeing transparency and reliability.


# Send Transaction

Most Trustless Work endpoints return an unsigned transaction in XDR format. This endpoint is used to sign such unsigned transactions and send them to the Stellar network.

### **Headers**

<table><thead><tr><th width="366">Name</th><th>Value</th></tr></thead><tbody><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>x-api-key</td><td><code>&#x3C;token></code></td></tr></tbody></table>

### **Open API**

## POST /helper/send-transaction

>

```json
{"openapi":"3.0.0","info":{"title":"Trustless Work API","version":"1.0"},"security":[{}],"paths":{"/helper/send-transaction":{"post":{"operationId":"HelperController_sendTransaction","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendTransaction"}}}},"responses":{"200":{"description":"The transaction has been successfully sent to the Stellar network","content":{"application/json":{}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized access"},"429":{"description":"Too Many Requests"},"500":{"description":"\n      <p>Possible errors:</p>\n      <ul>\n        <li>The transaction could not be sent to the Stellar network for some unknown reason. Please try again.</li>\n      </ul>","content":{"application/json":{}}}},"tags":["Helper"]}}},"components":{"schemas":{"SendTransaction":{"type":"object","properties":{"signedXdr":{"type":"string","description":"The sign's hash. This come from the wallet"}},"required":["signedXdr"]}}}}
```

### Use Example:

```typescript
import axios from "axios";

const http = axios.create({
  baseURL: "https://dev.api.trustlesswork.com",
  timeout: 10000,
  headers: {
    "Content-Type": "application/json",
    "x-api-key": your_api_key,
  },
});

export const useExample = async () => {
    // Get the signer address
    const { address } = await kit.getAddress();

    const response = await http.post(
      "/any-endpoint",
      {
        // body requested for the endpoint
      },
    ); 
    
    // Get the unsigned transaction hash
    const { unsignedTransaction } = response.data;

    // Sign the transaction by wallet
    const { signedTxXdr } = await signTransaction(unsignedTransaction, {
      address,
      networkPassphrase: WalletNetwork.TESTNET,
    });

    // Send the transaction to Stellar Network  <--------------- THIS
    const tx = await http.post("/helper/send-transaction", {
      signedXdr: signedTxXdr,
    });

    const { data } = tx;

    return data;
}
```


# Indexer

This endpoint facilitates the recovery and proper storage in Firebase of escrow-related information submitted to the Stellar Blockchain via external applications, bypassing the standard application.

### Key Components

* **External Transaction**: This endpoint handles cases where the XDR generated by any endpoint of our REST API is signed and sent directly by external applications.
* **Internal Queue**: Information initially generated by the application is stored in an internal queue, awaiting association with a specific transaction identified by its hash (`txHash`).
* **Firebase Storage**: Once retrieved from the internal queue, the information is permanently stored in Firebase.

### Roles Involved

* **External Application**: Signs and sends the XDR without using the standard endpoint (`helper/send-transaction`).
* **Indexer**: Responsible for retrieving information from the internal queue and storing it in Firebase upon receiving the transaction hash (`txHash`).

### Endpoint Workflow

1. The XDR is obtained from any transaction (not signed) generated with any of the endpoints of our REST API.
2. The generated XDR is signed and sent externally (without using `helper/send-transaction`).
3. The external application provides the corresponding `txHash`.
4. The `txHash` is sent to `indexer/update-from-txHash`.
5. The endpoint retrieves information stored in the internal queue and saves it in Firebase.

### Usage Example

* **Request**:

```json
{
  "txHash": "your-txHash-value"
}
```

* **Response**:

The information associated with the provided `txHash` is successfully stored in Firebase, ensuring the integrity of the generated escrow.

### Benefits of Usage

* Enables external integrations while maintaining information consistency.
* Prevents data loss when bypassing the standard workflow.
* Ensures secure and accurate storage in Firebase using the transaction hash.

This endpoint enhances the system's flexibility and robustness, ensuring all transactions, regardless of the method used, are adequately recorded in Firebase.

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


# Get Multiple Escrow Balance

Get the balance of multiple escrows.

### **Headers**

<table><thead><tr><th width="366">Name</th><th>Value</th></tr></thead><tbody><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>x-api-key</td><td><code>&#x3C;token></code></td></tr></tbody></table>

### **Open API**

## GET /helper/get-multiple-escrow-balance

>

```json
{"openapi":"3.0.0","info":{"title":"Trustless Work API","version":"1.0"},"security":[{}],"paths":{"/helper/get-multiple-escrow-balance":{"get":{"operationId":"HelperController_getMultipleEscrowBalance","parameters":[{"name":"addresses","required":true,"in":"query","description":"Array of addresses to query balances for","schema":{"type":"array","items":{}}}],"responses":{"200":{"description":"Collection of objects containing information on the balance of the requested addresses","content":{"application/json":{}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized access"},"429":{"description":"Too Many Requests"},"500":{"description":"\n      <p>Possible errors:</p>\n      <ul>\n        <li>Escrow not found</li>\n        <li>An unexpected error occurred</li>\n      </ul>","content":{"application/json":{}}}},"tags":["Helper"]}}}}
```

### Use Example:

```typescript
import axios from "axios";

const http = axios.create({
  baseURL: "https://dev.api.trustlesswork.com",
  timeout: 10000,
  headers: {
    "Content-Type": "application/json",
    "x-api-key": your_api_key,
  },
});

export const useExample = async (addresses: string[]) => {
  const response = await http.get("/helper/get-multiple-escrow-balance", {
    params: { addresses },
  });

  return response;
};

```


# Get Escrows By Contract Ids

Returns all the information of a security deposit requested through one or more requested contract ids.

### **Headers**

<table><thead><tr><th width="366">Name</th><th>Value</th></tr></thead><tbody><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>x-api-key</td><td><code>&#x3C;token></code></td></tr></tbody></table>

### Open API

## GET /helper/get-escrow-by-contract-ids

>

```json
{"openapi":"3.0.0","info":{"title":"Trustless Work API","version":"1.0"},"security":[{}],"paths":{"/helper/get-escrow-by-contract-ids":{"get":{"operationId":"HelperController_getEscrowsByContractId","parameters":[{"name":"contractIds","required":true,"in":"query","description":"Array of contract IDs to query","schema":{"type":"array","items":{"type":"string"}}},{"name":"isActive","required":false,"in":"query","description":"Is the escrow active","schema":{"type":"boolean"}},{"name":"validateOnChain","required":false,"in":"query","description":"When set to true, the endpoint will verify each escrow’s data against the blockchain to ensure accuracy and integrity. Enabling this adds an extra security layer but may increase the response time slightly due to the additional validation step","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Collection of data containing information from different scans requested by a signatory, role or contract ids.","content":{"application/json":{}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized access"},"429":{"description":"Too Many Requests"},"500":{"description":"\n      <p>Possible errors:</p>\n      <ul>\n        <li>The 'signer' parameter is required.</li>\n        <li>The 'contractIds' parameter is required.</li>\n        <li>No escrow found for contract ID CHASVBD...</li>\n        <li>Error fetching escrow by contract: CHASVBD...</li>\n        <li>An unexpected error occurred</li>\n      </ul>","content":{"application/json":{}}}},"tags":["Helper"]}}}}
```

### Use Example:

```typescript
import axios from "axios";

const http = axios.create({
  baseURL: "https://dev.api.trustlesswork.com",
  timeout: 10000,
  headers: {
    "Content-Type": "application/json",
    "x-api-key": your_api_key,
  },
});

export const useExample = async () => {
  const contractIds = [
    "CCR6HLU3LQMXOESNA6TOS2RZKGEBWQG3EN5FMZNC43RVXZWTTDCZ...",
    "CCA7WTCVCQ5JPKNIFSHPSJLJ3FJ3GKPNEVAIHP6T..."
  ];
  const validateOnChain = true;

  const params = new URLSearchParams();
  contractIds.forEach(id => params.append("contractIds[]", id));
  params.append("signer", signer);
  params.append("validateOnChain", validateOnChain.toString());

  const response = await http.get(`/helper/get-escrow-by-contract-ids?${params.toString()}`);
  return response;
}
```


# Get Escrows By Signer

Returns all the information of an escrow requested through the signer.

### **Headers**

<table><thead><tr><th width="366">Name</th><th>Value</th></tr></thead><tbody><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>x-api-key</td><td><code>&#x3C;token></code></td></tr></tbody></table>

### Open API

## GET /helper/get-escrows-by-signer

>

```json
{"openapi":"3.0.0","info":{"title":"Trustless Work API","version":"1.0"},"security":[{}],"paths":{"/helper/get-escrows-by-signer":{"get":{"operationId":"HelperController_getEscrowsBySigner","parameters":[{"name":"signer","required":false,"in":"query","description":"Address of the user who signed the transaction to create escrow","schema":{"type":"string"}},{"name":"role","required":false,"in":"query","description":"Role in escrow","schema":{"type":"string"}},{"name":"roleAddress","required":false,"in":"query","description":"Address of the user in the specified role","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","description":"Status of the escrow","schema":{"type":"string"}},{"name":"type","required":false,"in":"query","description":"Type of the escrow","schema":{"enum":["single-release","multi-release"],"type":"string"}},{"name":"engagementId","required":false,"in":"query","description":"Engagement ID of the escrow","schema":{"type":"string"}},{"name":"title","required":false,"in":"query","description":"Title of the escrow","schema":{"type":"string"}},{"name":"isActive","required":false,"in":"query","description":"Is the escrow active","schema":{"type":"boolean"}},{"name":"validateOnChain","required":false,"in":"query","description":"When set to true, the endpoint will verify each escrow’s data against the blockchain to ensure accuracy and integrity. Enabling this adds an extra security layer but may increase the response time slightly due to the additional validation step","schema":{"type":"boolean"}},{"name":"startDate","required":false,"in":"query","description":"Starting date range for filtering","schema":{"type":"string"}},{"name":"minAmount","required":false,"in":"query","description":"Minimum amount for filtering","schema":{"type":"number"}},{"name":"maxAmount","required":false,"in":"query","description":"Maximum amount for filtering","schema":{"type":"number"}},{"name":"orderBy","required":false,"in":"query","description":"Field to order the results by","schema":{"default":"createdAt","enum":["createdAt","updatedAt","amount"],"type":"string"}},{"name":"orderDirection","required":false,"in":"query","description":"Direction to order the results","schema":{"default":"desc","enum":["asc","desc"],"type":"string"}},{"name":"page","required":false,"in":"query","description":"Page number for pagination","schema":{"type":"number"}},{"name":"pageSize","required":false,"in":"query","description":"Number of items per page","schema":{"default":8,"type":"number"}},{"name":"contractID","required":false,"in":"query","description":"Contract Id of the deployed escrow","schema":{"type":"string"}},{"name":"endDate","required":false,"in":"query","description":"Ending date range for filtering","schema":{"type":"string"}}],"responses":{"200":{"description":"Collection of data containing information from different scans requested by a signatory, role or contract id.","content":{"application/json":{}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized access"},"429":{"description":"Too Many Requests"},"500":{"description":"\n      <p>Possible errors:</p>\n      <ul>\n        <li>Both startDate and endDate must be provided together.</li>\n        <li>Both minAmount and maxAmount must be provided together.</li>\n        <li>The 'signer' parameter is not supported for this endpoint. -> (In case of requesting escrows per role)</li>\n        <li>The information needed to filter by role is incomplete. -> (In case of requesting escrows per role)</li>\n        <li>The 'role' and 'roleAddress' parameters are not supported for this endpoint. -> (In case of requesting escrows per signer)</li>\n        <li>The 'signer' parameter is required. -> (In case of requesting escrows per signer)</li>\n        <li>An unexpected error occurred</li>\n      </ul>","content":{"application/json":{}}}},"tags":["Helper"]}}}}
```

### Use Example:

```typescript
import axios from "axios";

const http = axios.create({
  baseURL: "https://dev.api.trustlesswork.com",
  timeout: 10000,
  headers: {
    "Content-Type": "application/json",
    "x-api-key": your_api_key,
  },
});

export const useExample = async () => {

    const data = await http.get(
      "/escrow/single-release/get-escrows-by-signer?signer=GPUACN...." 👈🏼 // All required parameters are passed at the query level.
    ); 
  
    return data;
}
```


# Get Escrows By Role

Returns all the information of an escrow requested through the role.

### **Headers**

<table><thead><tr><th width="366">Name</th><th>Value</th></tr></thead><tbody><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>x-api-key</td><td><code>&#x3C;token></code></td></tr></tbody></table>

### Open API

## GET /helper/get-escrows-by-role

>

```json
{"openapi":"3.0.0","info":{"title":"Trustless Work API","version":"1.0"},"security":[{}],"paths":{"/helper/get-escrows-by-role":{"get":{"operationId":"HelperController_getEscrowsByRole","parameters":[{"name":"signer","required":false,"in":"query","description":"Address of the user who signed the transaction to create escrow","schema":{"type":"string"}},{"name":"role","required":false,"in":"query","description":"Role in escrow","schema":{"type":"string"}},{"name":"roleAddress","required":false,"in":"query","description":"Address of the user in the specified role","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","description":"Status of the escrow","schema":{"type":"string"}},{"name":"type","required":false,"in":"query","description":"Type of the escrow","schema":{"enum":["single-release","multi-release"],"type":"string"}},{"name":"engagementId","required":false,"in":"query","description":"Engagement ID of the escrow","schema":{"type":"string"}},{"name":"title","required":false,"in":"query","description":"Title of the escrow","schema":{"type":"string"}},{"name":"isActive","required":false,"in":"query","description":"Is the escrow active","schema":{"type":"boolean"}},{"name":"validateOnChain","required":false,"in":"query","description":"When set to true, the endpoint will verify each escrow’s data against the blockchain to ensure accuracy and integrity. Enabling this adds an extra security layer but may increase the response time slightly due to the additional validation step","schema":{"type":"boolean"}},{"name":"startDate","required":false,"in":"query","description":"Starting date range for filtering","schema":{"type":"string"}},{"name":"minAmount","required":false,"in":"query","description":"Minimum amount for filtering","schema":{"type":"number"}},{"name":"maxAmount","required":false,"in":"query","description":"Maximum amount for filtering","schema":{"type":"number"}},{"name":"orderBy","required":false,"in":"query","description":"Field to order the results by","schema":{"default":"createdAt","enum":["createdAt","updatedAt","amount"],"type":"string"}},{"name":"orderDirection","required":false,"in":"query","description":"Direction to order the results","schema":{"default":"desc","enum":["asc","desc"],"type":"string"}},{"name":"page","required":false,"in":"query","description":"Page number for pagination","schema":{"type":"number"}},{"name":"pageSize","required":false,"in":"query","description":"Number of items per page","schema":{"default":8,"type":"number"}},{"name":"contractID","required":false,"in":"query","description":"Contract Id of the deployed escrow","schema":{"type":"string"}},{"name":"endDate","required":false,"in":"query","description":"Ending date range for filtering","schema":{"type":"string"}}],"responses":{"200":{"description":"Collection of data containing information from different scans requested by a signatory, role or contract id.","content":{"application/json":{}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized access"},"429":{"description":"Too Many Requests"},"500":{"description":"\n      <p>Possible errors:</p>\n      <ul>\n        <li>Both startDate and endDate must be provided together.</li>\n        <li>Both minAmount and maxAmount must be provided together.</li>\n        <li>The 'signer' parameter is not supported for this endpoint. -> (In case of requesting escrows per role)</li>\n        <li>The information needed to filter by role is incomplete. -> (In case of requesting escrows per role)</li>\n        <li>The 'role' and 'roleAddress' parameters are not supported for this endpoint. -> (In case of requesting escrows per signer)</li>\n        <li>The 'signer' parameter is required. -> (In case of requesting escrows per signer)</li>\n        <li>An unexpected error occurred</li>\n      </ul>","content":{"application/json":{}}}},"tags":["Helper"]}}}}
```

### Use Example:

```typescript
import axios from "axios";

const http = axios.create({
  baseURL: "https://dev.api.trustlesswork.com",
  timeout: 10000,
  headers: {
    "Content-Type": "application/json",
    "x-api-key": your_api_key,
  },
});

export const useExample = async () => {

    const data = await http.get(
      "/escrow/single-release/get-escrows-by-role?role=approver?roleAddress=GPUACN...." 👈🏼 // All required parameters are passed at the query level.
    ); 
  
    return data;
}
```


# Update From Tx Hash

This endpoint allows you to change the properties of an escrow as long as a series of requirements are met, which will be mentioned in this section.

### Requirements for Use:

* You must have the valid `txHash` generated from a transaction sent directly to the Stellar network.
* The escrow data associated with this `txHash` must already exist in the internal queue.

### Headers

<table><thead><tr><th width="366">Name</th><th>Value</th></tr></thead><tbody><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>x-api-key</td><td><code>&#x3C;token></code></td></tr></tbody></table>

### Workflow:

1. The XDR is obtained from any transaction (not signed) generated with any of the endpoints of our REST API.
2. An unsigned XDR is generated and returned.
3. The XDR is signed externally and sent directly to Stellar.
4. The resulting `txHash` is retrieved.
5. The `txHash` is sent to `/indexer/update-from-txHash`.
6. The escrow information is retrieved from the internal queue and stored in Firebase.

### Open API

## PUT /indexer/update-from-txhash

>

```json
{"openapi":"3.0.0","info":{"title":"Trustless Work API","version":"1.0"},"security":[{}],"paths":{"/indexer/update-from-txhash":{"put":{"operationId":"IndexerController_updateFromTxHash","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveIndexedEscrowClass"}}}},"responses":{"200":{"description":"Returns the escrow object that was just saved/updated in the indexer and the success or failure of the response.","content":{"application/json":{}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized access"},"429":{"description":"Too Many Requests"},"500":{"description":"\n      <p>Possible errors:</p>\n      <ul>\n        <li>Error processing transaction b0e61d4...f1cb2d29: <error_message></li>\n        <li>An unexpected error occurred</li>\n      </ul>","content":{"application/json":{}}}},"tags":["Indexer"]}}},"components":{"schemas":{"SaveIndexedEscrowClass":{"type":"object","properties":{"txHash":{"type":"string","description":"Transaction hash"}},"required":["txHash"]}}}}
```

### Use Example:

```typescript
import axios from "axios";

const http = axios.create({
  baseURL: "https://dev.api.trustlesswork.com",
  timeout: 10000,
  headers: {
    "Content-Type": "application/json",
    "x-api-key": your_api_key,
  },
});

export const updateEscrowFromTxHash = async (txHash) => {
  const response = await http.post("/indexer/update-from-txHash", { txHash });
  return response.data;
};
```


# Introduction

A production-ready set of React blocks for integrating Trustless Work’s escrow flows.

{% hint style="info" %}
Want to customize the blocks?

Edit the generated components however you want.
{% endhint %}

***

### What you get

* UI blocks (cards/tables/dialogs/forms) to list and manage escrows
* Providers for API config, wallet context, dialogs and amounts
* TanStack Query hooks for fetching and mutating escrows
* Wallet-kit helpers and error handling utilities

### Links

{% embed url="<https://blocks.trustlesswork.com>" %}

{% embed url="<https://github.com/Trustless-Work/react-library-trustless-work-blocks>" %}

{% embed url="<https://www.npmjs.com/package/@trustless-work/blocks>" %}

### List all available blocks

Use the CLI to print all available blocks:

{% code title="CLI" %}

```sh
npx trustless-work list
```

{% endcode %}

This is the fastest way to discover folder paths for `npx trustless-work add ...`.

### Context API

The context API is a global storage of escrows. It is used to store the escrows that are fetched from the API. It is also used to store the selected escrow.

{% hint style="info" %}
You don’t have to use this context approach.

You can use Redux, Zustand, or anything else.\
Just make sure the target escrow data is available to each endpoint hook.
{% endhint %}

#### How the context is used by endpoint hooks

When implementing the endpoints, we need to pass the data of a specific escrow to each endpoint. But how do we do that? Our library provides a context called `EscrowContext`, which includes some very important utilities. Among them are`selectedEscrow`and `setSelectedEscrow`, which allow us to do the following:

#### `selectedEscrow`

Currently, `selectedEscrow` holds a specific escrow that we are pointing to. With this, all the endpoint hooks interact with that state in order to extract data from it, such as contractId, roles, etc. For example, in the change status select, the `milestoneIndex` values are loaded based on the currently selected escrow. Therefore, if`setSelectedEscrow` is undefined, they won't load.

{% code title="useChangeMilestoneStatus.ts" overflow="wrap" %}

```ts
const { selectedEscrow } = useEscrowContext();

const handleSubmit = form.handleSubmit(async (payload) => {             
  /**
   * Create the final payload for the change milestone status mutation
   *
   * @param payload - The payload from the form
   * @returns The final payload for the change milestone status mutation
  */
  const finalPayload: ChangeMilestoneStatusPayload = {
    contractId: selectedEscrow?.contractId || '', // contractId from the selectedEscrow
    milestoneIndex: payload.milestoneIndex,
    newStatus: payload.status,
    newEvidence: payload.evidence || undefined,
    serviceProvider: walletAddress || '',
  };

  /**
   * Call the change milestone status mutation
   *
   * @param payload - The final payload for the change milestone statusmutation
   * @param type - The type of the escrow
   * @param address - The address of the escrow
  */
  await changeMilestoneStatus.mutateAsync({
    payload: finalPayload,
    type: selectedEscrow?.type || 'multi-release',
    address: walletAddress || '',
  });
}
```

{% endcode %}

#### `setSelectedEscrow`

`setSelectedEscrow` stores the selected escrow in context.

Other hooks and UI blocks can then read `selectedEscrow` to get `contractId`, roles, etc.\
Example: cards view stores the selected escrow before opening the details dialog.

{% code title="EscrowsCards.tsx" overflow="wrap" %}

```ts
const { setSelectedEscrow } = useEscrowContext();

const onCardClick = (escrow: Escrow) => {
  setSelectedEscrow(escrow);
  dialogStates.second.setIsOpen(true);
};
```

{% endcode %}

#### `updateEscrow`

Our `updateEscrow` function update the existing selectedEscrow in the context. It is useful to update a flag or others fields. For example, we use it to update the escrow status after a change milestone status mutation.

{% code title="useChangeMilestoneStatus.ts" overflow="wrap" %}

```ts
const { selectedEscrow, updateEscrow } = useEscrowContext();

const handleSubmit = form.handleSubmit(async (payload) => { 
  /**
    * Call the change milestone status mutation
    *
    * @param payload - The final payload for the change milestone status mutation
    * @param type - The type of the escrow
    * @param address - The address of the escrow
  */
  await changeMilestoneStatus.mutateAsync({
    payload: finalPayload,
    type: selectedEscrow?.type || "multi-release", // type from the selectedEscrow
    address: walletAddress || "",
  });

  toast.success("Milestone status updated successfully");

  // Update the selected escrow in the context with the new status and evidence
  updateEscrow({
    ...selectedEscrow,
    milestones: selectedEscrow?.milestones.map((milestone, index) => {
      if (index === Number(payload.milestoneIndex)) {
        return {
          ...milestone,
          status: payload.status,
          evidence: payload.evidence || undefined,
        };
      }
      return milestone;
    }),
  });
}
```

{% endcode %}

### Install blocks by folder path

You can install whole folders (and all child blocks) with one command.

#### Install a parent directory

```sh
npx trustless-work add escrows
```

Installs all escrow blocks.

#### Install a specific subfolder

```sh
npx trustless-work add escrows/single-release
```

Installs only single-release escrow blocks.

{% hint style="success" %}
The deeper the folder path, the more specific the install.

Start broad (`escrows`), then narrow down as needed (`escrows/single-release/...`).
{% endhint %}

[Installation Guide](https://blocks.trustlesswork.com/get-started/installation)


# Getting Started

### Overview

Trustless Work Blocks is a set of React UI blocks, hooks, and providers.

It bundles (or expects) these core libraries:

* [**react-hook-form**](https://react-hook-form.com/) — Performant, flexible library for managing forms in React.
* [**zod**](https://zod.dev/) — TypeScript-first schema validation library.
* [**@trustless-work/escrow**](https://www.npmjs.com/package/@trustless-work/escrow) — SDK for handling escrow logic in decentralized apps.
* [**@tanstack/react-query**](https://tanstack.com/query/latest) — Data-fetching and caching library for React.
* [**@tanstack/react-query-devtools**](https://tanstack.com/query/latest/docs/react/guides/devtools) — Developer tools for inspecting React Query state.
* [**@hookform/resolvers**](https://react-hook-form.com/docs/useform/#resolver) — Resolvers for integrating validation libraries (like Zod) with React Hook Form.
* [**@creit.tech/stellar-wallets-kit**](https://www.npmjs.com/package/@creit.tech/stellar-wallets-kit) — Wallet connection toolkit for Stellar blockchain.
* [**axios**](https://axios-http.com/) — Promise-based HTTP client for making API requests.
* [**@tanstack/react-table**](https://tanstack.com/table/latest) — Headless table library for building flexible data grids.
* [**react-day-picker**](https://react-day-picker.js.org/) — Lightweight date picker component for React.
* [**recharts**](https://recharts.org/en-US/) — Charting library built with React and D3.

***

### Links

{% embed url="<https://www.npmjs.com/package/@trustless-work/blocks>" %}

### Setup

{% stepper %}
{% step %}

### Installation

Start by installing Trustless Work Blocks

{% tabs %}
{% tab title="npm" %}

```sh
npm install @trustless-work/blocks
```

{% endtab %}

{% tab title="yarn" %}

```sh
yarn add @trustless-work/blocks
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Initialize Configuration

Initialize your project with the CLI.

{% tabs %}
{% tab title="npm" %}

```sh
npx trustless-work init
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Configure Environment

The next step is to configure the Trustless Work provider. You need to configure the following:

* `baseURL`: Trustless Work API URL. Use `mainNet` or `development`.
* `apiKey`: Authorization provided by our dApp to use the API.

Create a provider that wraps your app with `TrustlessWorkConfig`.

{% code title="src/trustless-work-provider.tsx" overflow="wrap" fullWidth="true" %}

```typescript
"use client"; // make sure this is a client component

import React from "react";
import {
  // development environment = "https://dev.api.trustlesswork.com"
  development,

  // mainnet environment = "https://api.trustlesswork.com"
  mainNet,
  TrustlessWorkConfig,
} from "@trustless-work/escrow";

interface TrustlessWorkProviderProps {
  children: React.ReactNode;
}

export function TrustlessWorkProvider({
  children,
}: TrustlessWorkProviderProps) {
  /**
   * Get the API key from the environment variables
   */
  const apiKey = process.env.NEXT_PUBLIC_API_KEY || "";

  return (
    <TrustlessWorkConfig baseURL={development} apiKey={apiKey}>
      {children}
    </TrustlessWorkConfig>
  );
}

```

{% endcode %}

{% hint style="info" %}
Read-only flows can work without an API key.\
Write flows (deploy/fund/release/…) require a valid key.
{% endhint %}
{% endstep %}

{% step %}

### Wrap your app with providers

You must wrap your app with these providers:

* `ReactQueryClientProvider`
* `TrustlessWorkProvider`
* `WalletProvider`

If you want to use some blocks, you should wrap your app with their providers. See more in: [Dependencies](https://blocks.trustlesswork.com/get-started/dependencies)
{% endstep %}

{% step %}

### Add your First Component

Add wallet connectivity to your app:

```sh
npx trustless-work add wallet-kit
```

Example usage in a page:

{% code title="page.tsx" %}

```typescript
import { WalletButton } from "@/components/tw-blocks/wallet-kit/WalletButtons";

export default function HomePage() {
  return (
    <div className="container mx-auto py-8">
      <div className="flex justify-between items-center mb-8">
        <h1 className="text-3xl font-bold">My Escrows</h1>
        <WalletButton />
      </div>
    </div>
  );
}
```

{% endcode %}
{% endstep %}
{% endstepper %}

Now, you are able to interact with Trustless Work blocks.


# Single Release Lifecycle

Step by Step Guide to implement Escrow's Single Release Lifecycle

Important

It does not work for a real use case, only for testing purposes. But if you want to implement it, you can use the code below as a reference and customize it to your needs.

### Create a Next.js Project# <a href="#create-nextjs-project" id="create-nextjs-project"></a>

Start by creating a new Next.js project with TypeScript and Tailwind CSS. In order to make easier the setup, please use the path alias with "@/":

```
npx create-next-app@latest
```

Navigate to your project directory:

```
cd my-trustless-app
```

### Install Trustless Work Blocks# <a href="#install-trustless-work-blocks" id="install-trustless-work-blocks"></a>

Install the main library package:

npm

```
npm install @trustless-work/blocks
```

#### Run the CLI Setup <a href="#run-cli-setup" id="run-cli-setup"></a>

Initialize your project with the Trustless Work CLI:

```
npx trustless-work init
```

What the init command does:

* Installs shadcn/ui components (with interactive prompts)
* Installs required dependencies: @tanstack/react-query, @trustless-work/escrow, axios, zod, react-hook-form, @creit.tech/stellar-wallets-kit, react-day-picker, etc.
* Creates `.twblocks.json` configuration file
* Optionally wires providers into your Next.js `app/layout.tsx`

### Environment Configuration <a href="#environment-configuration" id="environment-configuration"></a>

[Documentation](https://docs.trustlesswork.com/trustless-work/developer-resources/authentication/request-api-key)

Create a `.env` file in your project root:

.env

```
# Required: Your Trustless Work API key 
NEXT_PUBLIC_API_KEY=your_api_key_here
```

### Add Wallet Connectivity <a href="#add-wallet-connectivity" id="add-wallet-connectivity"></a>

Add wallet connectivity to your app:

```
npx trustless-work add wallet-kit
```

#### Wrap your app with the WalletProvider: <a href="#wrap-app-wallet-provider" id="wrap-app-wallet-provider"></a>

Wrap your app with the WalletProvider in your layout.tsx:

app/layout.tsx

```
return (
    <WalletProvider>{children}</WalletProvider> 
);
```

#### Example usage in a page: <a href="#example-usage-wallet-page" id="example-usage-wallet-page"></a>

Add wallet connectivity to your app:

app/page.tsx

```
"use client";

import { WalletButton } from "@/components/tw-blocks/wallet-kit/WalletButtons";

export default function Home() {
  return (
    <div className="font-sans grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20">
      <header className="flex justify-between items-center w-full">
        <h2 className="text-2xl font-bold">Trustless Work</h2>

        {/* Wallet Button */}
        <WalletButton />
      </header>
    </div>
  );
}
```

### Add Helpers <a href="#add-helpers" id="add-helpers"></a>

Add helpers to your app:

```
npx trustless-work add helpers
```

### Add Tanstack Query <a href="#add-tanstack-query" id="add-tanstack-query"></a>

Add Tanstack Query to your app:

```
npx trustless-work add tanstack
```

### Add Handle Errors <a href="#add-handle-errors" id="add-handle-errors"></a>

Add Handle Errors to your app:

```
npx trustless-work add handle-errors
```

### Add Providers (If you skipped the init command) <a href="#add-providers" id="add-providers"></a>

Add Providers to your app:

```
npx trustless-work add providers
```

### Add Single Release Escrows Components <a href="#add-single-release-escrows" id="add-single-release-escrows"></a>

Add Single Release Escrows to your app:

```
npx trustless-work add escrows/single-release
```

### Add Single-Multi Release Escrows Components <a href="#add-single-multi-release-escrows" id="add-single-multi-release-escrows"></a>

Add Single-Multi Release Escrows to your app:

```
npx trustless-work add escrows/single-multi-release
```

### Add Escrows by Role Cards <a href="#add-escrows-by-role-cards" id="add-escrows-by-role-cards"></a>

Add Escrows by Role Cards to your app:

```
npx trustless-work add escrows/escrows-by-role/cards
```

#### Import Actions <a href="#import-actions" id="import-actions"></a>

In the code, there are some actions commented out. You can uncomment them and import them from the single-release block. See the notes in the escrows by role or by signer components.

#### Commented Out Code <a href="#commented-out-code" id="commented-out-code"></a>

escrows/escrows-by-role/details/Actions.tsx

```
return (
    <div className="flex items-start justify-start flex-col gap-2 w-full">
      {/* You can add the buttons here, using the buttons from the blocks. These actions are conditional based on the escrow flags and the user roles. */}
      {hasConditionalButtons && (
        <div className="flex flex-col gap-2 w-full">
          {/* UpdateEscrowDialog component should be rendered based on the escrow type. It means that if the selectedEscrow.type is "single-release", then the UpdateEscrowDialog (from the single-release block) component should be rendered. If the selectedEscrow.type is "multi-release", then the UpdateEscrowDialog (from the multi-release block) component should be rendered. */}
          {/* {shouldShowEditButton && <UpdateEscrowDialog />} */}

          {/* Works only with single-release escrows */}
          {/* Only appears if the escrow has balance */}
          {/* {shouldShowDisputeButton && <DisputeEscrowButton />} */}

          {/* Works only with single-release escrows */}
          {/* Only appears if the escrow is disputed */}
          {/* {shouldShowResolveButton && <ResolveDisputeDialog />} */}

          {/* Works only with single-release escrows */}
          {/* Only appears if all the milestones are approved */}
          {/* {shouldShowReleaseFundsButton && <ReleaseEscrowButton />} */}
        </div>
      )}

      <FundEscrowDialog />
    </div>
  );
```

#### Actions Imported <a href="#actions-imported" id="actions-imported"></a>

escrows/escrows-by-role/details/Actions.tsx

```
// If you need both types, you should import both versions to update escrow
import { UpdateEscrowDialog } from "../../single-release/update-escrow/dialog/UpdateEscrow";
/* import { UpdateEscrowDialog as UpdateEscrowDialogMultiRelease } from "../../multi-release/update-escrow/dialog/UpdateEscrow"; */
import { FundEscrowDialog } from "../../single-multi-release/fund-escrow/dialog/FundEscrow";
import { DisputeEscrowButton } from "../../single-release/dispute-escrow/button/DisputeEscrow";
import { ResolveDisputeDialog } from "../../single-release/resolve-dispute/dialog/ResolveDispute";
import { ReleaseEscrowButton } from "../../single-release/release-escrow/button/ReleaseEscrow";

return (
    <div className="flex items-start justify-start flex-col gap-2 w-full">
      {/* You can add the buttons here, using the buttons from the blocks. These actions are conditional based on the escrow flags and the user roles. */}
      {hasConditionalButtons && (
        <div className="flex flex-col gap-2 w-full">
          {/* UpdateEscrowDialog component should be rendered based on the escrow type. It means that if the selectedEscrow.type is "single-release", then the UpdateEscrowDialog (from the single-release block) component should be rendered. If the selectedEscrow.type is "multi-release", then the UpdateEscrowDialog (from the multi-release block) component should be rendered. */}
          {shouldShowEditButton && <UpdateEscrowDialog />}

          {/* Works only with single-release escrows */}
          {shouldShowDisputeButton && <DisputeEscrowButton />}

          {/* Works only with single-release escrows */}
          {shouldShowResolveButton && <ResolveDisputeDialog />}

          {/* Works only with single-release escrows */}
          {shouldShowReleaseFundsButton && <ReleaseEscrowButton />}
        </div>
      )}

      <FundEscrowDialog />
    </div>
  );
```

### Manual Provider Setup <a href="#manual-provider-setup" id="manual-provider-setup"></a>

Wrap your app with the required providers in this specific order:

app/layout.tsx

```
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import { ReactQueryClientProvider } from "@/components/tw-blocks/providers/ReactQueryClientProvider";
import { TrustlessWorkProvider } from "@/components/tw-blocks/providers/TrustlessWork";
import { WalletProvider } from "@/components/tw-blocks/wallet-kit/WalletProvider";
import { EscrowProvider } from "@/components/tw-blocks/providers/EscrowProvider";
import { EscrowDialogsProvider } from "@/components/tw-blocks/providers/EscrowDialogsProvider";
import { EscrowAmountProvider } from "@/components/tw-blocks/providers/EscrowAmountProvider";
import { Toaster } from "@/components/ui/sonner";

const geistSans = Geist({
  variable: "--font-geist-sans",
  subsets: ["latin"],
});

const geistMono = Geist_Mono({
  variable: "--font-geist-mono",
  subsets: ["latin"],
});

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body
        // optional: use geistSans.variable and geistMono.variable
        className="antialiased"
      >
        <ReactQueryClientProvider>
          <TrustlessWorkProvider>
            <WalletProvider>
              <EscrowProvider>
                <EscrowDialogsProvider>
                  <EscrowAmountProvider>
                    {children}

                    <Toaster />
                  </EscrowAmountProvider>
                </EscrowDialogsProvider>
              </EscrowProvider>
            </WalletProvider>
          </TrustlessWorkProvider>
        </ReactQueryClientProvider>
      </body>
    </html>
  );
}
```

Provider Order MattersThe providers must be nested in this exact order for proper functionality.

### Example usage in a page: <a href="#example-usage-complete-page" id="example-usage-complete-page"></a>

Now, you are able to interact with the entire escrow lifecycle.

app/page.tsx

```
"use client";

import { EscrowsByRoleCards } from "@/components/tw-blocks/escrows/escrows-by-role/cards/EscrowsCards";
import { InitializeEscrowDialog } from "@/components/tw-blocks/escrows/single-release/initialize-escrow/dialog/InitializeEscrow";
import { WalletButton } from "@/components/tw-blocks/wallet-kit/WalletButtons";

export default function Home() {
  return (
    <div className="font-sans grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20">
      <header className="flex justify-between items-center w-full">
        <h2 className="text-2xl font-bold">Trustless Work</h2>
        <WalletButton />
      </header>
      <main className="flex flex-col gap-[32px] row-start-2 items-center sm:items-start">
        <div className="container">
          <div className="flex w-full mb-4 justify-end">
            <div className="flex w-1/6">
              <InitializeEscrowDialog />
            </div>
          </div>

          <EscrowsByRoleCards />
        </div>
      </main>
    </div>
  );
}

```

All the blocks were added, now use them!You already have all the required blocks to start using the single-release escrow lifecycle.

### Final UI <a href="#final-ui" id="final-ui"></a>

By using these components, you'll be able to completed the entire escrow lifecycle.

Important Usage Advice- This cards components works **by role**. In the filters section, you can select the role you want to see the escrows for. Based on that, the actions buttons will be rendered.\
\- Before you start using the UI, you must add the **USDC** asset to your wallet. If not, you wont be able to interact with Trustless Work.

#### Wallet Connection Dialog <a href="#wallet-connection-dialog" id="wallet-connection-dialog"></a>

Show the wallet connection dialog:

![Escrow Lifecycle](https://blocks.trustlesswork.com/_next/image?url=%2Fstart-from-scratch%2Fwallet-kit.png\&w=1080\&q=75)

#### Cards by Role <a href="#cards-by-role" id="cards-by-role"></a>

Show the cards by role:

![Escrow Lifecycle](https://blocks.trustlesswork.com/_next/image?url=%2Fstart-from-scratch%2Fcards-by-role.png\&w=2048\&q=75)

#### Initialize Escrow Dialog <a href="#initialize-escrow-dialog" id="initialize-escrow-dialog"></a>

Show the initialize escrow dialog:

![Escrow Lifecycle](https://blocks.trustlesswork.com/_next/image?url=%2Fstart-from-scratch%2Finitialize-escrow.png\&w=2048\&q=75)

#### Escrow Details Dialog <a href="#escrow-details-dialog" id="escrow-details-dialog"></a>

Show the escrow details dialog:

![Escrow Lifecycle](https://blocks.trustlesswork.com/_next/image?url=%2Fstart-from-scratch%2Fdetails.png\&w=2048\&q=75)

The easiest way to implement escrows in blockchain."


# Dependent Blocks

Some blocks depend on shared modules (providers, helpers, query, etc).

Install the dependencies first.

{% hint style="warning" %}
If you skip dependencies, you’ll hit missing context errors at runtime.
{% endhint %}

### Dependency diagram

Use the interactive dependency diagram to confirm what a block needs.

{% embed url="<https://blocks.trustlesswork.com/get-started/dependencies>" %}

***

### Dependencies by block group

#### Listings (Escrows by Signer / Escrows by Role)

Applies to:

* Escrows by Signer: [Table](https://blocks.trustlesswork.com/blocks/escrows-escrows-by-signer-table), [Cards](https://blocks.trustlesswork.com/blocks/escrows-escrows-by-signer-cards)
* Escrows by Role: [Table](https://blocks.trustlesswork.com/blocks/escrows-escrows-by-role-table), [Cards](https://blocks.trustlesswork.com/blocks/escrows-escrows-by-role-cards)

Required modules:

* `wallet-kit`
* `providers`
* `handle-errors`
* `helpers`
* `tanstack`
* `escrows/single-release` or `escrows/multi-release` or `escrows/single-multi-release` (depends on which actions you want enabled)

{% hint style="info" %}
Include **all** providers for listings.

Listings open details dialogs and need the dialog + amount contexts.
{% endhint %}

{% code title="CLI (examples)" %}

```sh
# Core
npx trustless-work add wallet-kit
npx trustless-work add tanstack
npx trustless-work add providers

# Actions (pick what you need)
npx trustless-work add escrows/single-release
# npx trustless-work add escrows/multi-release
# npx trustless-work add escrows/single-multi-release

# Optional utility modules
npx trustless-work add handle-errors
npx trustless-work add helpers
```

{% endcode %}

#### Actions (single-release / multi-release)

All single-release and multi-release actions ([Initialize Escrow](https://blocks.trustlesswork.com/blocks/escrows-initialize-escrow), [Fund Escrow](https://blocks.trustlesswork.com/blocks/escrows-fund-escrow), [Change Milestone Status](https://blocks.trustlesswork.com/blocks/escrows-change-milestone-status), [Approve Milestone](https://blocks.trustlesswork.com/blocks/escrows-approve-milestone), [Release](https://blocks.trustlesswork.com/blocks/escrows-release-escrow), [Dispute](https://blocks.trustlesswork.com/blocks/escrows-dispute-escrow), [Resolve](https://blocks.trustlesswork.com/blocks/escrows-resolve-dispute), [Update Escrow](https://blocks.trustlesswork.com/blocks/escrows-update-escrow)) require:

* `wallet-kit`
* `providers`
* `handle-errors`
* `tanstack`
* `helpers`

{% code title="CLI (minimum for actions)" %}

```sh
npx trustless-work add wallet-kit
npx trustless-work add tanstack
npx trustless-work add providers

npx trustless-work add handle-errors
npx trustless-work add helpers
```

{% endcode %}

***

### Provider wrapping (order matters)

Wrap your app with these providers, in this exact order.

Include `EscrowDialogsProvider` and `EscrowAmountProvider` when you use dialogs or amount context.

{% hint style="danger" %}
Do not reorder providers.

Most “hooks not working” issues come from provider order.
{% endhint %}

{% code title="app/layout.tsx" overflow="wrap" %}

```tsx
import { ReactQueryClientProvider } from "@/components/tw-blocks/providers/ReactQueryClientProvider";
import { TrustlessWorkProvider } from "@/components/tw-blocks/providers/TrustlessWork";
import { WalletProvider } from "@/components/tw-blocks/wallet-kit/WalletProvider";
import { EscrowProvider } from "@/components/tw-blocks/providers/EscrowProvider";
import { EscrowDialogsProvider } from "@/components/tw-blocks/providers/EscrowDialogsProvider";
import { EscrowAmountProvider } from "@/components/tw-blocks/providers/EscrowAmountProvider";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <ReactQueryClientProvider>
          <TrustlessWorkProvider>
            <WalletProvider>
              <EscrowProvider>
                <EscrowDialogsProvider>
                  <EscrowAmountProvider>
                    {children}
                  </EscrowAmountProvider>
                </EscrowDialogsProvider>
              </EscrowProvider>
            </WalletProvider>
          </TrustlessWorkProvider>
        </ReactQueryClientProvider>
      </body>
    </html>
  );
}
```

{% endcode %}


# Wallet Kit

Wallet provider, validators and a connect button powered by Stellar Wallets Kit.

### Installation

Execute this command to add the code component.

{% tabs %}
{% tab title="npm" %}

```sh
npx trustless-work add wallet-kit
```

{% endtab %}
{% endtabs %}

### Interface

How does it look like?

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

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

### Important Notes

* This block is required for all escrow blocks. It is used to provide the wallet provider, validators and a connect button powered by Stellar Wallets Kit. @Credit-Tech
* When you already added the block to your project, you should add the USDC trustline to your Wallet. Otherwise, the escrow interaction will not work.
* If you don't want to use the escrowProvider context, you'll need to provide the payload through an alternative method.


# Escrows


# Escrows by Signer

Table and Cards layout to explore escrows by signer with sorting and filtering. This component contains a detailed view of the escrow, including the signer, status, and actions.

### Installation

Execute this command to add the code component.

{% tabs %}
{% tab title="npm" %}

```sh
npx trustless-work add escrows/escrows-by-signer/table
// or
npx trustless-work add escrows/escrows-by-signer/cards
```

{% endtab %}
{% endtabs %}


# Escrows by Role

Table and Cards layout to explore escrows by role with sorting and filtering. This component contains a detailed view of the escrow, including the signer, status, and actions.

### Installation

Execute this command to add the code component.

{% tabs %}
{% tab title="npm" %}

```sh
npx trustless-work add escrows/escrows-by-role/table
// or
npx trustless-work add escrows/escrows-by-role/cards
```

{% endtab %}
{% endtabs %}


# Initialize Escrow

Component to initialize an escrow with different variants and types.

## Single Release

### Installation

Execute this command to add the code component.

{% tabs %}
{% tab title="npm" %}

```sh
npx trustless-work add escrows/single-release/initialize-escrow/form
// or
npx trustless-work add escrows/single-release/initialize-escrow/dialog
```

{% endtab %}
{% endtabs %}

***

## Multi Release

### Installation

Execute this command to add the code component.

{% tabs %}
{% tab title="npm" %}

```sh
npx trustless-work add escrows/multi-release/initialize-escrow/form
// or
npx trustless-work add escrows/multi-release/initialize-escrow/dialog
```

{% endtab %}
{% endtabs %}


# Fund Escrow

Component to fund an escrow using form, button and dialog variants.

## Single & Multi Release

### Installation

Execute this command to add the code component.

{% tabs %}
{% tab title="npm" %}

```sh
npx trustless-work add escrows/single-multi-release/fund-escrow/form
// or
npx trustless-work add escrows/single-multi-release/fund-escrow/button
// or
npx trustless-work add escrows/single-multi-release/fund-escrow/dialog
```

{% endtab %}
{% endtabs %}


# Approve Milestone

Component to approve a milestone with form, button and dialog variants.

## Single & Multi Release

### Installation

Execute this command to add the code component.

{% tabs %}
{% tab title="npm" %}

```sh
npx trustless-work add escrows/single-multi-release/approve-milestone/form
// or
npx trustless-work add escrows/single-multi-release/approve-milestone/button
// or
npx trustless-work add escrows/single-multi-release/approve-milestone/dialog
```

{% endtab %}
{% endtabs %}


# Change Milestone Status

Component to change milestone status with form, button and dialog variants.

## Single & Multi Release

### Installation

Execute this command to add the code component.

{% tabs %}
{% tab title="npm" %}

```sh
npx trustless-work add escrows/single-multi-release/change-milestone-status/form
// or
npx trustless-work add escrows/single-multi-release/change-milestone-status/button
// or
npx trustless-work add escrows/single-multi-release/change-milestone-status/dialog
```

{% endtab %}
{% endtabs %}


# Release Funds

Action to release escrow funds.

## Single Release

### Installation

Execute this command to add the code component.

{% tabs %}
{% tab title="npm" %}

```sh
npx trustless-work add escrows/single-release/release-escrow/button
```

{% endtab %}
{% endtabs %}

***

## Multi Release

### Installation

Execute this command to add the code component.

{% tabs %}
{% tab title="npm" %}

```sh
npx trustless-work add escrows/multi-release/release-milestone/button
```

{% endtab %}
{% endtabs %}


# Dispute Escrow

Action to raise a dispute in the escrow or milestone.

## Single Release

### Installation

Execute this command to add the code component.

{% tabs %}
{% tab title="npm" %}

```sh
npx trustless-work add escrows/single-release/dispute-escrow/button
```

{% endtab %}
{% endtabs %}

***

## Multi Release

### Installation

Execute this command to add the code component.

{% tabs %}
{% tab title="npm" %}

```sh
npx trustless-work add escrows/multi-release/dispute-milestone/button
```

{% endtab %}
{% endtabs %}


# Resolve Dispute

Component to resolve disputes with form, button and dialog variants.

## Single Release

### Installation

Execute this command to add the code component.

{% tabs %}
{% tab title="npm" %}

```sh
npx trustless-work add escrows/single-release/resolve-dispute/form
// or
npx trustless-work add escrows/single-release/resolve-dispute/button
// or
npx trustless-work add escrows/single-release/resolve-dispute/dialog
```

{% endtab %}
{% endtabs %}

***

## Multi Release

### Installation

Execute this command to add the code component.

{% tabs %}
{% tab title="npm" %}

```sh
npx trustless-work add escrows/multi-release/resolve-dispute/form
// or
npx trustless-work add escrows/multi-release/resolve-dispute/button
// or
npx trustless-work add escrows/multi-release/resolve-dispute/dialog
```

{% endtab %}
{% endtabs %}


# Update Escrow

Component to update escrow configuration with form and dialog variants.

## Single Release

### Installation

Execute this command to add the code component.

{% tabs %}
{% tab title="npm" %}

```sh
npx trustless-work add escrows/single-release/update-escrow/form
// or
npx trustless-work add escrows/single-release/update-escrow/dialog
```

{% endtab %}
{% endtabs %}

***

## Multi Release

### Installation

Execute this command to add the code component.

{% tabs %}
{% tab title="npm" %}

```sh
npx trustless-work add escrows/multi-release/update-escrow/form
// or
npx trustless-work add escrows/multi-release/update-escrow/dialog
```

{% endtab %}
{% endtabs %}


# Withdraw Remaining Funds

Component to withdraw remaining funds with form, button and dialog variants.

## Multi Release

### Installation

Execute this command to add the code component.

{% tabs %}
{% tab title="npm" %}

```sh
npx trustless-work add escrows/multi-release/withdraw-remaining-funds/form
// or
npx trustless-work add escrows/multi-release/withdraw-remaining-funds/button
// or
npx trustless-work add escrows/multi-release/withdraw-remaining-funds/dialog
```

{% endtab %}
{% endtabs %}


# Dashboard

Component to show the basic dashboard of the escrows by signer.

### Installation

Execute this command to add the code component.

{% tabs %}
{% tab title="npm" %}

```sh
npx trustless-work add escrows/dashboard/dashboard-01
```

{% endtab %}
{% endtabs %}


# Indicators

Component to show the balance progress of the escrow based on the target.

### Installation

Execute this command to add the code component.

{% tabs %}
{% tab title="npm" %}

```sh
npx trustless-work add escrows/indicators/balance-progress/bar
// or
npx trustless-work add escrows/indicators/balance-progress/donut
```

{% endtab %}
{% endtabs %}


# Introduction

### Quick links

<table data-view="cards"><thead><tr><th>Title</th><th data-card-target data-type="content-ref">Link</th></tr></thead><tbody><tr><td>Getting started</td><td><a href="/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/rxYPNF9iKlXPgPA9et2e">/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/rxYPNF9iKlXPgPA9et2e</a></td></tr><tr><td>Request an API key</td><td><a href="/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/rk6FfPZG0cVD1uYYThg4">/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/rk6FfPZG0cVD1uYYThg4</a></td></tr><tr><td>API basics (base URLs, Swagger, limits)</td><td><a href="/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/zjyQfhCFZuBXwRacP8gA">/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/zjyQfhCFZuBXwRacP8gA</a></td></tr><tr><td>NPM package</td><td><a href="https://www.npmjs.com/package/@trustless-work/escrow">https://www.npmjs.com/package/@trustless-work/escrow</a></td></tr><tr><td>GitHub repo</td><td><a href="https://github.com/Trustless-Work/react-library-trustless-work">https://github.com/Trustless-Work/react-library-trustless-work</a></td></tr></tbody></table>

### Overview

This SDK is a React/TypeScript client for Trustless Work.

It wraps the Trustless Work API with hooks and typed payloads.

{% hint style="info" %}
Most write calls return an **unsigned XDR**. Your app must sign it client-side.
{% endhint %}

### What you’ll do with the SDK

* Initialize escrows (single-release or multi-release).
* Fund, approve, change milestone status, release, dispute, resolve.
* Query and index escrows with helper endpoints.


# Getting Started

### Overview

The Trustless Work React SDK is a collection of hooks and typed entities.

It uses [Axios](https://axios-http.com/docs/intro) for HTTP requests.

{% hint style="info" %}
Write flows require an API key (`NEXT_PUBLIC_API_KEY`). Read-only calls can work without one.
{% endhint %}

### Quick links

<table data-view="cards"><thead><tr><th>Title</th><th data-card-target data-type="content-ref">Link</th></tr></thead><tbody><tr><td>NPM package</td><td><a href="https://www.npmjs.com/package/@trustless-work/escrow">https://www.npmjs.com/package/@trustless-work/escrow</a></td></tr><tr><td>API basics (base URLs, Swagger, limits)</td><td><a href="/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/zjyQfhCFZuBXwRacP8gA">/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/zjyQfhCFZuBXwRacP8gA</a></td></tr><tr><td>Send signed transactions (XDR)</td><td><a href="/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/FB7WlcHJgllJlGOLvLpo">/spaces/Dg2e2YCRmNlhCnxxmEb6/pages/FB7WlcHJgllJlGOLvLpo</a></td></tr></tbody></table>

### Setup

{% stepper %}
{% step %}

### Installation

Install the SDK.

{% tabs %}
{% tab title="npm" %}

```sh
npm install "@trustless-work/escrow"
```

{% endtab %}

{% tab title="yarn" %}

```sh
yarn add "@trustless-work/escrow"
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Configure the provider

You’ll configure 2 things:

* `baseURL`: use `development` (testnet) or `mainNet` (mainnet).
* `apiKey`: from the BackOffice dApp.

The SDK exports `TrustlessWorkConfig`. Wrap your app with it to enable all hooks.

{% code title="src/trustless-work-provider.tsx" overflow="wrap" fullWidth="true" %}

```typescript
"use client"; // make sure this is a client component

import React from "react";
import {
  // development environment = "https://dev.api.trustlesswork.com"
  development,

  // mainnet environment = "https://api.trustlesswork.com"
  mainNet,
  TrustlessWorkConfig,
} from "@trustless-work/escrow";

interface TrustlessWorkProviderProps {
  children: React.ReactNode;
}

export function TrustlessWorkProvider({
  children,
}: TrustlessWorkProviderProps) {
  const apiKey = process.env.NEXT_PUBLIC_API_KEY || "";

  return (
    <TrustlessWorkConfig baseURL={development} apiKey={apiKey}>
      {children}
    </TrustlessWorkConfig>
  );
}

```

{% endcode %}

{% hint style="warning" %}
If you render this provider on the server, hooks will break. Keep it in a client component.
{% endhint %}
{% endstep %}

{% step %}

### Wrap your app

Pick the snippet that matches your setup.

{% tabs %}
{% tab title="Next.js (App Router)" %}
{% code title="app/layout.tsx" %}

```typescript
import { TrustlessWorkProvider } from "@/trustless-work-provider";
 
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <TrustlessWorkProvider>{children}</TrustlessWorkProvider>
      </body>
    </html>
  );
}
```

{% endcode %}
{% endtab %}

{% tab title="React (SPA)" %}
{% code title="src/app.tsx" %}

```typescript
import { TrustlessWorkProvider } from "./trustless-work-provider";
 
export function App() {
  return (
    <TrustlessWorkProvider>
      <YourApp />
    </TrustlessWorkProvider>
  );
}
```

{% endcode %}
{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Use hooks and entities

You can now call SDK hooks from any component under the provider.

Typical flow:

1. Call a hook to get an **unsigned XDR**.
2. Sign the XDR with the correct role wallet.
3. Submit it with `useSendTransaction`.

Read: [useSendTransaction](/trustless-work/escrow-react-sdk/usesendtransaction).
{% endstep %}
{% endstepper %}

{% hint style="success" %}
This SDK supports **single-release** and **multi-release** escrows. Use the correct hook + payload type for each flow.
{% endhint %}


# useSendTransaction

Most Trustless Work endpoints return an unsigned transaction in XDR format. This endpoint is used to sign such unsigned transactions and send them to the Stellar network.

{% hint style="info" %}
This endpoint must be used for all the endpoints after we execute it. Except getEscrowBalances, getEscrowsByContractId, getEscrowsByRole and getEscrowsBySigner .
{% endhint %}

## Usage

This custom hook exposes a function to send a signed transaction to the network.&#x20;

{% code overflow="wrap" %}

```typescript
import { useSendTransaction} from "@trustless-work/escrow/hooks";

/*
 *  useSendTransaction
*/
const { sendTransaction } = useSendTransaction();

/* 
 * It returns a SendTransactionResponse
 * payload should be of type string
*/
const data = await sendTransaction(signedXdr);

```

{% endcode %}

### Function

* `sendTransaction`\
  Responsible for building and returning data based on the provided payload.

*Argument:*

`payload`: An string containing the required fields to send a transaction to the network.

{% content-ref url="/pages/mCiAw7wa82TjvbS32nkX" %}
[Types](/trustless-work/introduction/developer-resources/types)
{% endcontent-ref %}

*Return Value:*

**For:** Fund Escrow, Resolve Dispute, Change Milestone Status, Change Milestone Approved Flag, Start Dispute, Release Funds:

* This object will be a type of *sendTransactionResponse*.&#x20;

**For:** Initialize Escrow:

* This object will be a type of *sendTransactionResponse*. But you can set it as *InitializeEscrowResponse*.

**For:** Update Escrow:

* This object will be a type of *sendTransactionResponse*. But you can set it as *UpdateEscrowResponse*.

***

## Usage Example

{% code title="src/hooks/useSendTransactionForm.ts" overflow="wrap" %}

```typescript
import {
  useFundEscrow,
  useSendTransaction,
} from "@trustless-work/escrow/hooks";
import {
  useSomeEndpointPayload
} from "@trustless-work/escrow/types";

export const useSomeEndpointForm= () => {

 /*
  *  useSomeEndpoint
 */
 const { someFunction } = useSomeEndpoint();
 
 /*
  *  useSendTransaction
 */
 const { sendTransaction } = useSendTransaction();

/*
 * onSubmit function, this could be called by form button
*/
 const onSubmit = async (payload: useSomeEndpointPayload) => {

    try {
      // get unsignedTransaction from some endpoint ...

      /**
       * @Note:
       * - We need to sign the transaction using your [private key] such as wallet
       * - The result will be a signed transaction
       */
      const signedXdr = await signTransaction({ /* This method should be provided by the wallet */
        unsignedTransaction,
        address: walletAddress || "",
      });

      if (!signedXdr) {
        throw new Error("Signed transaction is missing.");
      }

      /**
       * @Note:
       * - We need to send the signed transaction to the API
       * - The data will be an SendTransactionResponse
       */
      const data = await sendTransaction(signedXdr);

    } catch (error: unknown) {
      // catch error logic
    }
  };
}

```

{% endcode %}


# Escrows




---

[Next Page](/trustless-work/llms-full.txt/1)

