API · Corporate plan

Connect your systems to Plensity

Create clients and proposals from your CRM, track where every proposal stands and download the signed PDF and its certificate, without opening the app.

Getting started

  1. 1In Plensity, an admin goes to Settings → API and creates a key. It is shown only once: store it somewhere safe.
  2. 2Every call carries the key in the header Authorization: Bearer pls_….
  3. 3Check it works with GET /me: it returns your company name and the key’s access level.
Base URL
https://app.plensity.io/api/v1

Keys and access

  • Read only: query and download. Read and write: also create and update.
  • A key only sees your company’s data and acts on behalf of the admin who created it: changes are logged in the audit trail as “API: key name”.
  • It stops working immediately if it is revoked, if its creator is no longer an admin, or if the company leaves the Corporate plan.
  • Plensity does not store the key, only a fingerprint. If it is lost, revoke it and create a new one.

Format

  • JSON requests and responses (Content-Type: application/json).
  • Dates in ISO 8601. Amounts as numbers, in the currency given.
  • Lists are paginated with limit (up to 200, default 50) and offset, and return {"data": [...], "total", "limit", "offset"}.
  • Up to 120 calls per minute per key. Beyond that, 429 rate_limited: wait a moment and retry.

Reference

GET/me

Clients

GET/clients

List clients. Filter with q (name or sector).

GET/clients/{id}

One client.

POST/clientswrite

Create a client. name is required; also sector, contact_name, contact_role, contact_email and contact_phone. If one with that name already exists (ignoring case and accents), it is not duplicated: the existing one is returned with 200 and already_existed: true.

PATCH/clients/{id}write

Update the fields you send.

Proposals

GET/proposals

List proposals. Filter with status, client_id and updated_since (ISO 8601 date).

GET/proposals/{id}

One proposal with its services, whether the client opened it (tracking), whether and by whom it was signed (signature), and links to the PDF and the certificate. Each service says how it is charged in billing (fixed, per_day, monthly, per_unit), recurring_monthly is the monthly fee and amount is the full contract value, before tax.

POST/proposalswrite

Create a draft proposal, like «+ New proposal». client_id is required; also title, description (what the client asks for), deadline (YYYY-MM-DD), owner_email (who handles it) and template_id.

PATCH/proposals/{id}write

Change the status with status (and lost_reason when lost). Same rules as in Plensity: a draft cannot become won, and nothing goes out without the approved margin.

GET/proposals/{id}/pdf

The PDF. Once sent, the one the client received.

GET/proposals/{id}/signature-certificate

The signature certificate. 404 not_signed if it is not signed.

Proposal statuses
draftgeneratedsentclient_approvedwonlostcancelled

Example

curl "https://app.plensity.io/api/v1/proposals/42" \
  -H "Authorization: Bearer pls_…"
{
  "id": 42,
  "reference": "REF-2026-042",
  "title": "Servicio gestionado 2027",
  "client_id": 7,
  "client_name": "Transportes Aldama",
  "status": "sent",
  "amount": 24900.0,
  "currency": "EUR",
  "sent_at": "2026-09-21T10:14:03",
  "tracking": {
    "opened": true,
    "views": 3,
    "first_opened_at": "2026-09-21T11:02:40",
    "last_opened_at": "2026-09-24T08:31:12"
  },
  "signature": { "signed": false, "signed_at": null, "signer_name": null, "signer_email": null, "signer_company": null },
  "recurring_monthly": 2075.0,
  "services": [{
    "name": "Servicio gestionado", "type": "managed", "price": 24900.0,
    "billing": { "type": "monthly", "unit_price": 2075.0, "quantity": 12, "unit": null }
  }],
  "links": {
    "pdf": "https://app.plensity.io/api/v1/proposals/42/pdf",
    "signature_certificate": null
  }
}
curl -X POST "https://app.plensity.io/api/v1/proposals" \
  -H "Authorization: Bearer pls_…" \
  -H "Content-Type: application/json" \
  -d '{"title": "Renovación 2027", "client_id": 7,
       "deadline": "2027-01-31",
       "owner_email": "laura@tuempresa.com"}'

Errors

Always the same shape. With validation_failed, fields explains what is wrong with each field.

{
  "error": {
    "code": "validation_failed",
    "message": "…",
    "fields": { "client_id": "…" }
  }
}
400invalid_jsonThe body is not a JSON object.
400invalid_parameterA URL parameter is not valid.
401unauthorizedThe key is missing.
401invalid_keyThe key does not exist or was revoked.
401key_owner_inactiveThe key’s creator is no longer an active admin.
403plan_requiredYour plan does not include the API.
403read_only_keyThe key is read only.
404not_foundIt does not exist, or it is not your company’s.
404not_signedThe proposal is not signed.
405method_not_allowedThat method does not exist on that route.
409invalid_transitionThat status change is not allowed.
410goneNo longer exists. Opportunities were removed: everything comes from proposals (<code>/proposals</code>).
422validation_failedSome fields are not valid.
429rate_limitedToo many calls: wait a moment.
500server_errorSomething went wrong in Plensity: retry in a moment.

Want to be notified?

To know right away when a proposal is sent, changes status or is won, without polling, set up a webhook in Settings → Webhooks: Plensity calls your system when it happens.

Email us about Corporate
← Back to home