---
title: "Add a milestone"
method: POST
path: "/api/v1/milestones"
tags: ["Milestones"]
---

# Add a milestone

`POST /api/v1/milestones`

## Request

- Base URL: `https://www.vestiarion.xyz`
- URL: `https://www.vestiarion.xyz/api/v1/milestones`
- Auth: HTTP bearer

Adds work a contractor is to be paid for, checked by the rules of the console's Add milestone form, and recorded in the ledger as `create_milestone` with `via: "api"` and the key's id. It is added as the key's issuer's: if the agent holds it on its own judgment, someone other than the issuer must choose Pay now, unless the issuer is the workspace's only approver.

It starts `pending`, and the API cannot verify it. A GitHub pull request in `verificationSource` is checked by the agent, which verifies the milestone once the pull request is merged; any other link is evidence for the person who verifies it on Contractors. Once it is verified, the agent decides the payment with every guardrail, and pays only to the contractor's confirmed address. A `contractorId` the workspace does not hold, or a client's, answers `400`.

## Headers

- `Idempotency-Key` string

## Request body

- CreateMilestoneRequest: A milestone to add. It starts pending: the agent pays it only once it is verified, by GitHub or by a person, and only after its own checks.
  - `contractorId` string, required: The `id` of the contractor or vendor to pay, from `GET /api/v1/counterparties` or from the answer that added it. A client is not paid for milestones.
  - `title` string, required: What was delivered, 3 to 160 characters.
  - `amount` union, required: What the work is paid, in USDC, with at most 6 decimal places. A decimal string such as `"250.00"` keeps it exact; a number is read the same way.
    - string
    - number
  - `verificationSource` string: A link to the delivered work: https, up to 500 characters. A GitHub pull request (`https://github.com/<owner>/<repo>/pull/<number>`) is checked by the agent, which verifies the milestone once it is merged. Any other link is evidence for the person who verifies the milestone on Contractors.

## Response `201`

Created

- CreateMilestoneResponse
  - `data` object, required: A contractor milestone, how it was verified, and whether it was paid.
    - `id` string, required
    - `title` string, required
    - `amount` number, required
    - `status` 'pending' | 'verified' | 'paid' | 'held' | 'closed', required
    - `verificationSource` string, nullable, required
    - `verificationMethod` 'unverified' | 'github' | 'manual' | 'seed' | 'asana', required
    - `verificationStatus` 'unverified' | 'verified' | 'not_merged' | 'unavailable' | 'failed', required
    - `verificationCheckedAt` string, nullable, required
    - `verifiedAt` string, nullable, required
    - `verificationDetail` object, required
    - `verified` boolean, required
    - `decidedAt` string, nullable, required
    - `settledAt` string, nullable, required
    - `closedAt` string, nullable, required: When a person closed the milestone without paying it (status closed), else null.
    - `closeReason` string, nullable, required: The reason the person gave for closing it without paying, else null.
    - `agentReasoning` string, nullable, required
    - `txHash` string, nullable, required: An on-chain hash when the payment settled on Arc, else null.
    - `contractor` object, nullable, required
      - `id` string, required
      - `name` string, required
      - `riskLevel` string, required
    - `createdAt` string, required

## Other responses

- `400`: invalid_request
- `401`: unauthorized
- `403`: forbidden
- `409`: conflict
- `429`: rate_limited
- `500`: internal

---

[API](https://skmtc.dev/vestiarion/apis/vestiarion-api.md) · [All operations](https://skmtc.dev/vestiarion/apis/vestiarion-api/llms.txt) · [OpenAPI document](https://skmtc.dev/vestiarion/apis/vestiarion-api/revisions/fd2f589dac9b?raw)
