Customers
Customer endpoints let a partner resolve a Loyva customer_id from an external client id or email address, and store
general-purpose documents against a customer outside the e-sign/vault lifecycle.
All partner customer endpoints are mounted under /api/v2/partner/* and authenticated with
X-API-Key: lk_.... Every successful response is wrapped in { "data": ... }.
Look up a customer
GET/partner/customers
Required scope: customers:read
Query parameters: exactly one of client_id (your external client id — the external_client_id column of the client bulk upload; case-insensitive) or email.
Returns a partner-safe subset of customer fields for the org owning the API key. Internal-only
fields (notes, stripe_customer_id, properties, revenue metrics) are never returned.
Response:
{
"data": {
"customer_id": "cust_abc123",
"name": "Jane Buyer",
"email": "buyer@example.com",
"phone": "555-0100",
"company": "Acme Corp",
"job_title": "Operations Manager",
"entity_type": "individual",
"client_id": null,
"category": null,
"industry": null,
"address_line1": null,
"address_line2": null,
"city": null,
"state": null,
"postal_code": null,
"country": null,
"website_url": null,
"primary_contact_name": null,
"created_at": "2026-03-01T09:00:00.000Z",
"updated_at": "2026-03-01T09:00:00.000Z"
}
}
If no customer matches, this returns 404:
{ "error": "Customer not found" }
If several customers share the email, this returns 409 with the candidates; look them up by client_id instead:
{
"error": "Several customers match this email. Look up by client_id instead.",
"candidates": [
{ "customer_id": "cust_abc123", "name": "Vail Commons C1", "client_id": "314-090" },
{ "customer_id": "cust_def456", "name": "Vail Commons C2", "client_id": "314-091" }
]
}
Upload a document to a customer's general folder
POST/partner/customers/:customer_id/documents
Required scope: envelopes:write
Accepts multipart/form-data with a single file field. Allowed types: application/pdf,
image/png, image/jpeg. Max 50 MB. The type is determined from the file's content, not the multipart Content-Type: a file whose bytes aren't a PDF/PNG/JPEG is rejected with 415. PDFs are stored with embedded JavaScript, launch/submit actions and attachments removed; a PDF that can't be parsed (e.g. password-protected) is rejected with 422.
Use this for documents that aren't part of an e-sign or vaulting flow — e.g. a scanned intake form or an externally-signed contract you just want stored against the customer. They land in the customer's "General Files" view in the Loyva dashboard.
Optional form fields, applied when a Loyva user later sends the document for signature:
| Field | Type | Description |
|---|---|---|
name | string | Document name shown in Loyva and in signing emails. Defaults to the file name. |
signers | JSON string | Optional. [{ "email", "name", "role" }, …] in signing order. Saved on the document: Send for Signature in the Loyva app opens with these signers and roles already filled in, and POST /partner/envelopes/:id/send uses them when called without signers. For a PDF whose fields are tagged with roles, each role must be one the document names (else 422). Emails and roles must be unique. |
auto_vault_enabled | "true" / "false" | Vault the signed document automatically once every party signs. Records intent only — the sender still accepts the Vault-In Certification Terms before sending, and nothing is vaulted without that acceptance. |
kba_required | "true" / "false" | Require Knowledge-Based Authentication from every signer (billed per verified signer). The sender can still change it until the document is prepared for signature. |
Both default to false; any other value returns 422. They are echoed back in the response.
curl -X POST "https://api.stg.loyva.net/api/v2/partner/customers/cust_abc123/documents" \
-H "X-API-Key: lk_..." \
-F "file=@./intake-form.pdf"
Response: 201 Created
{
"data": {
"customer_id": "cust_abc123",
"envelope_id": "env_x7k9m2p4q1w3",
"name": "intake-form.pdf",
"signers": [],
"path": "org_abc/env_x7k9m2p4q1w3/upload_20260427120000.pdf",
"hash": "<sha256>",
"size": 184320,
"contentType": "application/pdf",
"auto_vault_enabled": false,
"kba_required": false
}
}
To send the document for signature without the Loyva app, call
POST /partner/envelopes/:id/send
with the returned envelope_id.
Internally this creates an envelope record (status: "uploaded", is_upload: true,
directory_id: null) to hold the file — it will appear in GET /partner/envelopes
like any other envelope — but it is never dispatched through DocuSeal and is not vaulted unless
you separately call one of the vault-in endpoints.
If customer_id doesn't belong to your org (or doesn't exist), this returns 404:
{ "error": "Customer not found" }