> For the complete documentation index, see [llms.txt](https://docs.trustlesswork.com/trustless-work/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.trustlesswork.com/trustless-work/v2-en/api-rest/deploy/manage-milestones.md).

# Manage Milestones

### Requirements to use:

1. Only the entity with the admin role has permissions to execute this endpoint.
2. milestoneUpdates (editing existing milestones) is not allowed while the escrow holds funds. In that case, only newMilestones can be sent.
3. At least one of the two arrays (newMilestones or milestoneUpdates) must be non-empty.

### 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>

### New Milestone:

| Name            | Type                          | Description                                                                                                               |
| --------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| description     | string                        | Text describing the function of the milestone.                                                                            |
| status          | string (default: "pending")   | Milestone status. Ex: Approved, In dispute, etc...                                                                        |
| evidence        | string (optional)             | Evidence reference (URL, IPFS hash, etc.) attached to the milestone                                                       |
| approvalsTarget | number (optional, default: 1) | Number of distinct approvers required to consider the milestone approved. Must be ≥ 1 and ≤ the length of roles.approvers |

Milestone Update

| Name           | Type                      | Description                                                     |
| -------------- | ------------------------- | --------------------------------------------------------------- |
| index          | number                    | 0-based position of the milestone to update within the escrow   |
| newDescription | string \| null (optional) | New description for the milestone. Pass null to leave unchanged |

### Open API

## Add new milestones and/or edit existing milestone descriptions

> Single endpoint that ADDS new milestones (\`newMilestones\`) and EDITS descriptions of existing ones (\`milestoneUpdates\`) in one atomic transaction. At least one of the two arrays must be non-empty. Description-only updates are forbidden while the escrow holds funds. Admin signs.

```json
{"openapi":"3.0.0","info":{"title":"👋🏼 Trustless Work Core API — All Endpoints (Unified)","version":"1.0"},"security":[{}],"paths":{"/escrow/single-release/v2/manage-milestones":{"post":{"description":"Single endpoint that ADDS new milestones (`newMilestones`) and EDITS descriptions of existing ones (`milestoneUpdates`) in one atomic transaction. At least one of the two arrays must be non-empty. Description-only updates are forbidden while the escrow holds funds. Admin signs.","operationId":"ManageMilestonesV2Controller_manage","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManageMilestonesV2Dto"}}}},"responses":{"200":{"description":"Unsigned XDR built successfully.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnsignedTransactionResponse"}}}},"400":{"description":"Request body or query params fail schema validation (wrong type, missing required field, unknown property).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetailsResponseDto"}}}},"401":{"description":"Missing, malformed, expired, revoked or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetailsResponseDto"}}}},"403":{"description":"API key is valid but does not have the role required for this operation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetailsResponseDto"}}}},"422":{"description":"Payload is well-formed but a business rule rejects it (e.g. amount out of range, role not allowed for this user).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetailsResponseDto"}}}},"500":{"description":"Unexpected server-side failure. Use the `traceId` to look up the incident in server logs or contact support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetailsResponseDto"}}}}},"summary":"Add new milestones and/or edit existing milestone descriptions","tags":["Single Release Escrow V2"]}}},"components":{"schemas":{"ManageMilestonesV2Dto":{"type":"object","properties":{"contractId":{"type":"string","description":"Deployed v2 escrow contract (C...)."},"admin":{"type":"string","description":"Admin wallet — signs the transaction."},"newMilestones":{"description":"Brand-new milestones appended to the escrow (up to 50 after merge).","type":"array","items":{"$ref":"#/components/schemas/MilestoneV2Dto"}},"milestoneUpdates":{"description":"Description-only updates against existing milestones (up to 50). Forbidden while the escrow holds funds — the contract returns `MilestoneUpdateNotAllowedWithFunds`.","type":"array","items":{"$ref":"#/components/schemas/MilestoneDescriptionUpdateV2Dto"}}},"required":["contractId","admin","newMilestones","milestoneUpdates"]},"MilestoneV2Dto":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable milestone description."},"status":{"type":"string","description":"Initial status. Convention: pending → in_progress → completed. Defaults to \"pending\"."},"approvalsTarget":{"type":"number","description":"Number of distinct approvers required for the milestone. Must be > 0 and ≤ roles.approvers.length. Defaults to 1."}},"required":["description"]},"MilestoneDescriptionUpdateV2Dto":{"type":"object","properties":{"index":{"type":"number","description":"Zero-based index of the milestone to update."},"newDescription":{"type":"string","description":"New milestone description. When absent, the contract leaves the previous description unchanged.","maxLength":500}},"required":["index"]},"UnsignedTransactionResponse":{"type":"object","properties":{"unsignedXdr":{"type":"string","description":"Base64-encoded unsigned XDR. Sign it with the appropriate wallet and submit to Soroban / Horizon to execute the operation on-chain."},"txHash":{"type":"string","description":"SHA-256 hash of the prepared transaction. NOTE: it only matches the executed transaction if you sign the XDR exactly as returned — re-preparing (re-simulating) it changes the hash. Prefer `contractId` for correlation when present."},"contractId":{"type":"object","description":"Deploys only: the address (C…) the new escrow contract WILL have once this transaction executes — known upfront because the service generates the deploy salt. Track your escrow with it (e.g. `GET /escrows/:contractId`) as soon as the transaction lands; it is stable even if your wallet/SDK re-prepares the transaction.","nullable":true}},"required":["unsignedXdr","txHash"]},"ProblemDetailsResponseDto":{"type":"object","properties":{"type":{"type":"string","description":"Stable URI identifying the error type. Hash-link points to the docs."},"title":{"type":"string","description":"Short human-readable summary of the problem."},"status":{"type":"number","description":"HTTP status code, repeated here for typed clients."},"code":{"type":"string","description":"Machine-readable error code. Stable across versions; safe to switch on."},"detail":{"type":"string","description":"Human-readable explanation specific to this occurrence."},"instance":{"type":"string","description":"URI of the request that triggered the error."},"traceId":{"type":"string","description":"Correlation id propagated from the `X-Trace-Id` header (or generated). Use it when contacting support to reference a specific request."},"extensions":{"type":"object","description":"Optional structured context. Shape depends on the error code; documented per-endpoint when relevant.","additionalProperties":true}},"required":["type","title","status","code","detail"]}}}}
```

<figure><picture><source srcset="/files/hDeFNDCpbrqGRFUEOcRr" media="(prefers-color-scheme: dark)"><img src="/files/9KSQLFDH5nTuMqcVNIrF" alt=""></picture><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:

{% code collapsedlinecount="10" %}

```typescript
import axios from "axios";

  const http = axios.create({
    baseURL: "https://beta.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/v2/manage-milestones",
        {
          // 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("/stellar/send-transaction", {
        signedXdr: signedTxXdr,
      });

      const { data } = tx;

      return data;
```

{% endcode %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.trustlesswork.com/trustless-work/v2-en/api-rest/deploy/manage-milestones.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
