Vezmo App

Customers & catalog

Client projects

A client project is the work under an accepted proposal: a title, an agreed amount, dates and milestones for one of your clients. When your client accepts a proposal, Vezmo creates its project for you. You can also create projects yourself.

  • A project made by an acceptance starts IN_PROGRESS, with the proposal's title, description, amount, currency and charge type, the contract's dates, and an empty deliveryMilestones list. The proposal.accepted webhook carries its id as clientProjectId.
  • Invoices attach to a project with clientProjectId (see Create invoice). An invoice must use its project's currency.
  • Projects belong to the user your API key belongs to. Another business's project answers 404.
  • A project has a mode too: one an accepted proposal starts is of the proposal's mode, and one you create takes your key's. A key sees only its own mode's projects (the other mode's answer 404, with the message No such client project: a similar object exists in live mode, but a test mode key was used to make this request. for one your business has in the other mode), and a project links only to a proposal of its own mode.

Every response is the usual envelope: { success, message, data, requestId, timestamp }. amount comes back as a decimal string, such as "1200".

Required API-key permissions

  • client-project.read — list, retrieve and list deleted projects.
  • client-project.create — create a project.
  • client-project.update — update and restore a project.
  • client-project.delete — delete a project.

All four are in the default client-project permission group, so new keys have them. Send the access token from Create token as Authorization: Bearer <token>.

Create a project

POST /merchant/client-project

FieldTypeRequiredRules
clientIdstringyesOne of your clients. Another id answers 404 “Client not found”.
proposalIdstringnoOne of your proposals, else 404. A free link: the proposal's status and client aren't checked.
titlestringyesNot empty.
descriptionstringnoScope and deliverables.
amountnumberyesThe agreed amount in major units: 0 or more, at most 2 decimals, and at most the equivalent of 1,000,000 USD in its currency. 0 means no budget is set.
currencystringnoA supported currency, such as USD (the default), EUR or GBP.
statusenumnoDRAFT, OPEN, IN_PROGRESS (the default), ON_HOLD, REVISION, PENDING, COMPLETED or CANCELLED. For your own tracking.
chargeTypeenumnoFIXED (the default), HOURLY, CUSTOM or RECURRING.
startDatedatenoISO 8601, such as 2026-01-15.
endDatedatenoISO 8601, such as 2026-03-31.
deliveryMilestonesarray of objectsnoAt most 100 entries, stored as given, such as [{ "name": "Design", "dueDate": "2026-02-01" }].
Request
curl -X POST https://api.vezmo.com/api/v1/merchant/client-project \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": "cm2x8k1qz0002abcd1234efgh",
    "title": "Website redesign",
    "description": "New marketing site + CMS",
    "amount": 1200,
    "currency": "USD",
    "startDate": "2026-01-15",
    "endDate": "2026-03-31",
    "deliveryMilestones": [{ "name": "Design", "dueDate": "2026-02-01" }]
  }'
201 Created
{
  "success": true,
  "message": "Project created successfully",
  "data": {
    "id": "cmb1proj0001abcd",
    "clientId": "cm2x8k1qz0002abcd1234efgh",
    "userId": "cm2usr000001abcd",
    "proposalId": null,
    "title": "Website redesign",
    "description": "New marketing site + CMS",
    "amount": "1200",
    "currency": "USD",
    "status": "IN_PROGRESS",
    "chargeType": "FIXED",
    "delevery_milestones": [{ "name": "Design", "dueDate": "2026-02-01" }],
    "deliveryMilestones": [{ "name": "Design", "dueDate": "2026-02-01" }],
    "startDate": "2026-01-15T00:00:00.000Z",
    "endDate": "2026-03-31T00:00:00.000Z",
    "createdAt": "2026-01-10T09:00:00.000Z",
    "updatedAt": "2026-01-10T09:00:00.000Z",
    "deletedAt": null
  },
  "requestId": "9b2f6c1e-4d3a-4f7b-8e21-5c6d7a8b9c0d",
  "timestamp": "2026-01-10T09:00:00.000Z"
}

Every read of a project carries the milestones twice: as deliveryMilestones, and as delevery_milestones, the field's original misspelled name, kept for older integrations. Use deliveryMilestones. A write still accepts the old name; when both are sent, deliveryMilestones wins.

List projects

GET /merchant/client-project — your live projects, newest first. Deleted projects are left out.

FieldTypeRequiredRules
clientIdstringnoOnly this client's projects.
searchstringnoMatches the title (case-insensitive).
statusenumnoOne project status, as in Create.
chargeTypeenumnoFIXED, HOURLY, CUSTOM or RECURRING.
sortByenumnoamount or createdAt (the default).
orderenumnoasc or desc (the default).
pageintegerno1 or more. Default 1.
limitintegerno1 or more. Default 10, at most 100; a bigger value returns 100.
Request
curl "https://api.vezmo.com/api/v1/merchant/client-project?status=IN_PROGRESS&page=1&limit=10" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
200 OK
{
  "success": true,
  "message": "Project All retrieved",
  "data": {
    "data": [
      {
        "id": "cmb1proj0001abcd",
        "title": "Website redesign",
        "amount": "1200",
        "currency": "USD",
        "status": "IN_PROGRESS",
        "deliveryMilestones": [{ "name": "Design", "dueDate": "2026-02-01" }],
        "…": "the other project fields, as in Retrieve",
        "client": { "id": "cm2x8k1qz0002abcd1234efgh", "name": "Acme Ltd", "…": "the full client record" },
        "proposal": null
      }
    ],
    "pagination": {
      "total": 1,
      "page": 1,
      "limit": 10,
      "totalPages": 1,
      "nextPage": null,
      "prevPage": null
    }
  },
  "requestId": "…",
  "timestamp": "…"
}

In the list, client and proposal are the full records; Retrieve returns a shorter version of each. Follow pagination.nextPage until it is null.

Retrieve a project

GET /merchant/client-project/{id}

FieldTypeRequiredRules
idstring, pathyesThe project's id.
Request
curl https://api.vezmo.com/api/v1/merchant/client-project/cmb1proj0001abcd \
  -H "Authorization: Bearer $ACCESS_TOKEN"
200 OK
{
  "success": true,
  "message": "Project retrieved",
  "data": {
    "id": "cmb1proj0001abcd",
    "clientId": "cm2x8k1qz0002abcd1234efgh",
    "userId": "cm2usr000001abcd",
    "proposalId": "cm2prop00001abcd",
    "title": "Website redesign",
    "description": "New marketing site + CMS",
    "amount": "1200",
    "currency": "USD",
    "status": "IN_PROGRESS",
    "chargeType": "FIXED",
    "delevery_milestones": [{ "name": "Design", "dueDate": "2026-02-01" }],
    "deliveryMilestones": [{ "name": "Design", "dueDate": "2026-02-01" }],
    "startDate": "2026-01-15T00:00:00.000Z",
    "endDate": "2026-03-31T00:00:00.000Z",
    "createdAt": "2026-01-10T09:00:00.000Z",
    "updatedAt": "2026-01-10T09:00:00.000Z",
    "deletedAt": null,
    "client": {
      "id": "cm2x8k1qz0002abcd1234efgh",
      "name": "Acme Ltd",
      "email": "billing@acme.example.com",
      "phone": null,
      "company": "Acme",
      "country": "US",
      "status": "ACTIVE",
      "profile_image": null
    },
    "proposal": {
      "id": "cm2prop00001abcd",
      "proposalNo": "VP-000123",
      "title": "Website redesign",
      "amount": "1200",
      "currency": "USD",
      "status": "ACCEPTED",
      "chargeType": "FIXED",
      "createdAt": "2026-01-05T09:00:00.000Z"
    }
  },
  "requestId": "…",
  "timestamp": "…"
}

A deleted project answers 404 here. Find it with List deleted projects.

Update a project

PATCH /merchant/client-project/{id} — send any of the Create fields; only those change.

FieldTypeRequiredRules
idstring, pathyesThe project's id.
clientId, proposalIdstringnoAs in Create: yours, else 404.
currencystringnoCan't change once the project has invoices (400).
amountnumbernoAs in Create, checked in the currency the project ends up with.
startDate, endDatedatenoISO 8601. null clears it.
deliveryMilestonesarray of objectsnoReplaces the whole list.
title, description, status, chargeTypeas in CreatenoAs in Create.
Request
curl -X PATCH https://api.vezmo.com/api/v1/merchant/client-project/cmb1proj0001abcd \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "status": "COMPLETED", "endDate": "2026-03-20" }'
200 OK
{
  "success": true,
  "message": "Project retrieved",
  "data": {
    "id": "cmb1proj0001abcd",
    "status": "COMPLETED",
    "endDate": "2026-03-20T00:00:00.000Z",
    "deliveryMilestones": [{ "name": "Design", "dueDate": "2026-02-01" }],
    "…": "the other project fields, as in Create"
  },
  "requestId": "…",
  "timestamp": "…"
}

Delete a project

DELETE /merchant/client-project/{id} — moves the project to the trash. Its invoices are kept. Restore brings it back.

FieldTypeRequiredRules
idstring, pathyesThe project's id.
Request
curl -X DELETE https://api.vezmo.com/api/v1/merchant/client-project/cmb1proj0001abcd \
  -H "Authorization: Bearer $ACCESS_TOKEN"
200 OK
{
  "success": true,
  "message": "Project retrieved",
  "data": {
    "id": "cmb1proj0001abcd",
    "clientId": "cm2x8k1qz0002abcd1234efgh",
    "userId": "cm2usr000001abcd",
    "proposalId": null,
    "title": "Website redesign",
    "description": "New marketing site + CMS",
    "amount": "1200",
    "currency": "USD",
    "status": "IN_PROGRESS",
    "chargeType": "FIXED",
    "delevery_milestones": [{ "name": "Design", "dueDate": "2026-02-01" }],
    "startDate": "2026-01-15T00:00:00.000Z",
    "endDate": "2026-03-31T00:00:00.000Z",
    "createdAt": "2026-01-10T09:00:00.000Z",
    "updatedAt": "2026-03-22T14:05:00.000Z",
    "deletedAt": "2026-03-22T14:05:00.000Z"
  },
  "requestId": "…",
  "timestamp": "…"
}

Delete and Restore return the project row on its own: no client or proposal, and the milestones only as delevery_milestones.

List deleted projects

GET /merchant/client-project/trash — your deleted projects, with the ids Restore needs. It takes the same query as List projects.

FieldTypeRequiredRules
clientIdstringnoOnly this client's projects.
searchstringnoMatches the title (case-insensitive).
statusenumnoOne project status, as in Create.
chargeTypeenumnoFIXED, HOURLY, CUSTOM or RECURRING.
sortByenumnoamount or createdAt (the default).
orderenumnoasc or desc (the default).
pageintegerno1 or more. Default 1.
limitintegerno1 or more. Default 10, at most 100; a bigger value returns 100.
Request
curl "https://api.vezmo.com/api/v1/merchant/client-project/trash?page=1&limit=10" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
200 OK
{
  "success": true,
  "message": "Trashed projects retrieved",
  "data": {
    "data": [
      {
        "id": "cmb1proj0001abcd",
        "title": "Website redesign",
        "deletedAt": "2026-03-22T14:05:00.000Z",
        "…": "the other project fields, with client and proposal, as in List"
      }
    ],
    "pagination": { "total": 1, "page": 1, "limit": 10, "totalPages": 1, "nextPage": null, "prevPage": null }
  },
  "requestId": "…",
  "timestamp": "…"
}

Restore a project

PATCH /merchant/client-project/{id}/restore — brings a deleted project back, unchanged.

FieldTypeRequiredRules
idstring, pathyesThe project's id.
Request
curl -X PATCH https://api.vezmo.com/api/v1/merchant/client-project/cmb1proj0001abcd/restore \
  -H "Authorization: Bearer $ACCESS_TOKEN"
200 OK
{
  "success": true,
  "message": "Project restored",
  "data": {
    "id": "cmb1proj0001abcd",
    "clientId": "cm2x8k1qz0002abcd1234efgh",
    "userId": "cm2usr000001abcd",
    "proposalId": null,
    "title": "Website redesign",
    "description": "New marketing site + CMS",
    "amount": "1200",
    "currency": "USD",
    "status": "IN_PROGRESS",
    "chargeType": "FIXED",
    "delevery_milestones": [{ "name": "Design", "dueDate": "2026-02-01" }],
    "startDate": "2026-01-15T00:00:00.000Z",
    "endDate": "2026-03-31T00:00:00.000Z",
    "createdAt": "2026-01-10T09:00:00.000Z",
    "updatedAt": "2026-03-23T08:30:00.000Z",
    "deletedAt": null
  },
  "requestId": "…",
  "timestamp": "…"
}

Not on the API

Project stats and a project's payments are in the dashboard only. For a project's payments, list its invoices with GET /merchant/invoice?clientProjectId=….

Errors

StatusWhen
400A field fails its rules: a bad enum, date, page or limit, a negative or too-large amount, or an unsupported currency. Also “This project already has invoices, so its currency can't be changed.”
401 / 403No token, an expired one, or a key without the route's scope.
404“Project not found”: not yours, or deleted (Retrieve, Update, Delete). “Client not found” or “Proposal not found” for a clientId or proposalId that isn't yours.
404 Not Found
{
  "success": false,
  "message": "Project not found",
  "errors": [{ "code": "http.404", "message": "Project not found", "statusCode": 404 }],
  "data": null,
  "requestId": "…",
  "timestamp": "…"
}

See Errors for the error body.