eva crm Public API
Leads

Attachments

Photos and PDFs on a lead, stored and displayed exactly like a staff upload in the CRM.

POST Upload attachments

POST/v1/leads/{id}/attachments

Attaches up to ten files to a lead in one multipart/form-data request. They are stored and shown in the CRM exactly like a staff upload, in the photo view for images. Files cannot be sent with the lead payload: create the lead first, then post the files to its id.

Path parameters
idstring · uuidRequired

The lead's id from create or list.

Headers
Idempotency-Keystring · max 200

Makes a retry safe: the same key on the same lead returns 200 with created: false and the files from the first call, without storing anything. Send the retry exactly as before. Recommended.

Request bodymultipart/form-data — no other parts are accepted
filesfile · 1 to 10Required

Repeat the part for several files. JPEG, PNG, WebP, GIF, HEIC/HEIF and PDF, decided by the file's content, not its name. 25 MB each, 50 MB per request.

documentTypestring · id or name

Files the whole batch under a document type from list categories; the category comes with the type. Images without one go to the organisation's Photos category, as the CRM does; anything else is left uncategorized.

commentstring

Applies to every file in the batch.

Responses
201
Stored. `data` lists the files in the order sent, with signed `urls` that expire at `urlsExpireAt`.
200
The `Idempotency-Key` was seen before on this lead; the first upload's files, `created: false`.
404
No such lead in your organisation.
413
Too many files, a file over 25 MB, or a request over 50 MB.
422
A file of a type not accepted, named; or a `documentType` that is unknown, ambiguous, or restricted to named staff. Nothing from the request is stored.
503
Attachments are not enabled on this environment. Leads keep working.
Example request
curl https://api.evacrm.co.uk/v1/leads/1e4e3f90-4384-42ce-90c3-540db5343964/attachments \
  -H "Authorization: Bearer sk_..." \
  -H "Idempotency-Key: order-8812-photos" \
  -F "files=@front.jpg" -F "files=@survey.pdf" -F "comment=Site survey" -F "documentType=Survey report"
Example response · 201
{
  "created": true,
  "lead": { "id": "1e4e3f90-4384-42ce-90c3-540db5343964", "code": "L013898" },
  "data": [
    {
      "id": "9c1b6e4a-…",
      "attachmentId": "5d0f2c77-…",
      "name": "front.jpg",
      "type": "image",
      "mimeType": "image/jpeg",
      "size": 2481733,
      "photoNo": "001",
      "comment": "Site survey",
      "category": { "id": "6d2a…", "name": "Surveys" },
      "documentType": { "id": "b41c…", "name": "Survey report" },
      "source": "api",
      "createdAt": "2026-09-02T11:14:03.512+01:00",
      "urls": {
        "download": "https://…",
        "thumbnail": "https://…",
        "medium": "https://…",
        "large": "https://…"
      },
      "urlsExpireAt": "2026-09-02T12:14:03.512+01:00"
    },
    {
      "id": "…", "name": "survey.pdf", "type": "document", "mimeType": "application/pdf",
      "size": 88213, "photoNo": null, "urls": { "download": "https://…" }
    }
  ]
}

What is accepted

The type of each file is decided by its content, not its name or the Content-Type of the part. Accepted: JPEG, PNG, WebP, GIF, HEIC/HEIF and PDF. SVG is not. A file that does not match is a 422 naming it, and nothing from that request is stored. name comes back with the extension the bytes warrant.

What happens to images

Images get the same thumbnail, medium and large versions the CRM makes for its own uploads, so they appear in the CRM's photo view like any staff upload. photoNo is the CRM's per-lead numbering (L013898-001.jpg), reserved in order within the request. HEIC is converted to JPEG on arrival. Image metadata, including GPS position if present, is kept, as it is for staff uploads; strip it before sending if you do not want it stored.

urls are signed and expire at urlsExpireAt, an hour after the response. They are for fetching now, not storing; GET the list again for fresh ones.

Filing

The CRM files documents in categories (folders, which can be nested) containing document types. Send documentType as a type's id or name and the batch is filed under it; the category comes with the type, since every type belongs to exactly one. Names match case-insensitively; a name that exists under more than one category is a 422 asking for the id. A type the CRM restricts to named staff is refused, because files under it would be hidden from this API afterwards. Both come back as category and documentType on every file, null when unset.

GET List categories

GET/v1/leads/attachments/categories

The document categories and types your organisation offers on a lead, archived ones excluded, each type marked restricted when the CRM limits it to named staff. parent links a nested category to the one it sits in. No parameters. Cached for five minutes.

Responses
200
The categories, each with its `types`.
Example request
curl https://api.evacrm.co.uk/v1/leads/attachments/categories \
  -H "Authorization: Bearer sk_..."
Example response · 200
{
  "object": "list",
  "data": [
    {
      "id": "6d2a…",
      "name": "Surveys",
      "description": null,
      "parent": null,
      "types": [
        { "id": "b41c…", "name": "Survey report", "description": null, "restricted": false },
        { "id": "0f9e…", "name": "Structural calculations", "description": null, "restricted": true }
      ]
    },
    { "id": "7c11…", "name": "Photos", "description": null, "parent": null, "types": [] }
  ]
}

GET List attachments

GET/v1/leads/{id}/attachments

Everything attached to the lead, whoever uploaded it, newest first, in the file shape above. source says where a file came from: api, web (the CRM) or mobile. Files filed under a document type the CRM restricts to named staff are omitted. Capped at 500, not paginated.

Path parameters
idstring · uuidRequired

The lead's id.

Responses
200
`data`, the files, each with fresh signed `urls`.
404
No such lead in your organisation.
Example request
curl https://api.evacrm.co.uk/v1/leads/1e4e3f90-4384-42ce-90c3-540db5343964/attachments \
  -H "Authorization: Bearer sk_..."
Example response · 200
{
  "object": "list",
  "data": [
    {
      "id": "9c1b6e4a-2f7d-4c3e-8a1b-5d6e7f8a9b0c",
      "attachmentId": "5d0f2c77-…",
      "name": "front.jpg",
      "type": "image",
      "mimeType": "image/jpeg",
      "size": 2481733,
      "photoNo": "001",
      "comment": "Site survey",
      "category": {
        "id": "6d2a…",
        "name": "Surveys"
      },
      "documentType": {
        "id": "b41c…",
        "name": "Survey report"
      },
      "source": "api",
      "createdAt": "2026-09-02T11:14:03.512+01:00",
      "urls": {
        "download": "https://…",
        "thumbnail": "https://…",
        "medium": "https://…",
        "large": "https://…"
      },
      "urlsExpireAt": "2026-09-02T12:14:03.512+01:00"
    },
    {
      "id": "…",
      "attachmentId": "5d0f2c77-…",
      "name": "survey.pdf",
      "type": "document",
      "mimeType": "application/pdf",
      "size": 88213,
      "photoNo": null,
      "comment": "Site survey",
      "category": {
        "id": "6d2a…",
        "name": "Surveys"
      },
      "documentType": {
        "id": "b41c…",
        "name": "Survey report"
      },
      "source": "api",
      "createdAt": "2026-09-02T11:14:03.512+01:00",
      "urls": {
        "download": "https://…"
      },
      "urlsExpireAt": "2026-09-02T12:14:03.512+01:00"
    }
  ]
}

DEL Delete an attachment

DEL/v1/leads/{id}/attachments/{fileId}

Removes one file, its derivatives, and its entry in the CRM. Only files that came through this API can be deleted through it.

Path parameters
idstring · uuidRequired

The lead's id.

fileIdstring · uuidRequired

The file's id from the upload or list response.

Responses
200
Deleted. The body carries `deleted: true` and the file id.
403
The file was uploaded by staff, not through the API.
404
No such file on this lead, or it was already deleted.
Example request
curl -X DELETE https://api.evacrm.co.uk/v1/leads/1e4e3f90-4384-42ce-90c3-540db5343964/attachments/9c1b6e4a-2f7d-4c3e-8a1b-5d6e7f8a9b0c \
  -H "Authorization: Bearer sk_..."
Example response · 200
{
  "deleted": true,
  "id": "9c1b6e4a-2f7d-4c3e-8a1b-5d6e7f8a9b0c"
}

On this page