Copy a document and share a view link

A document runs exactly one transaction, so a copy is what gives you a second run — of a finished agreement, or of a master document you keep and copy per counterparty. A view link then lets somebody read a document without a Circularo account. This guide does both in two calls.

Before you begin

  • A document to copy. The examples copy an employment agreement that carries a category, metadata and one attachment.

  • Copying attachments needs the view_attachments right. Without it the copy is still created, just without the attachments.

Step 1: Copy the document

Cloning takes no input beyond the document you are copying:

POST /documents/pXq4NcYBhK9tWdA2mFzR/clone
Authorization: Bearer YOUR_API_KEY
HTTP/2 201

{
    "id": "hL8vXe3RmQ7zBnT5wKdY",
    "title": "Copy of Employment Agreement (template)",
    "category": "Contract",
    "metadataDefinition": "d_employment",
    "metadataFields": {
        "D_EMPLOYMENT_DEPARTMENT": "Engineering"
    },
    "attachments": [
        {
            "fileId": "f21b7e9d54a0c836be47d0a95c1e628f",
            "fileName": "Benefits summary",
            "isMerged": false,
            "isPublic": false,
            "mimeType": "application/pdf",
            "pageCount": 3,
            "size": 818513
        }
    ],
    "mainFile": {
        "fileId": "8d3f60ba14c7e295db0a7f36e14b95c2",
        "fileName": "Employment Agreement (template)",
        "mimeType": "application/pdf",
        "pageCount": 1,
        "size": 1852
    },
    "folders": [
        {
            "folderId": null,
            "scope": "personal"
        }
    ],
    "transaction": {
        "id": "Kd3PmZq8XvR5wTnB6hLc",
        "status": "not-started",
        "waitingFor": []
    },
    "templateId": null,
    ...
}

A few things to notice:

  • The copy is made from the document's current state — content, metadata, field values and attachments come along, and the title gains a Copy of prefix.

  • The copy owns its files: mainFile.fileId and the attachment identifiers are new, so working on one document never touches the other.

  • transaction is a fresh one — a different id, back to not-started. Nothing tied to the original's transaction comes along: the fields placed for its recipients and the files they submitted are left behind, so the copy's own transaction places its fields anew.

  • templateId is the one binding cloning does not release. It is null here because no template governs either document; had the original been created from a template, the copy would stay bound to the same one.

folders shows where the copy landed: the root of your personal tree, because the request named no target. Pass folderId or scope to place it somewhere else.

A view link is created by asking the document for one:

POST /documents/hL8vXe3RmQ7zBnT5wKdY/link
Authorization: Bearer YOUR_API_KEY
HTTP/2 201

{
    "shareToken": "82c5fa30d26bc80b828c2c6e8ced7f2655b0f1539a25a8ac888ccc75b30363f0",
    "shareUrl": "https://sandbox.circularo.com/share?shareToken=82c5fa30d26bc80b828c2c6e8ced7f2655b0f1539a25a8ac888ccc75b30363f0"
}

shareUrl is ready to hand out — it opens the document, read-only, in the Circularo web app, and the recipient needs no account and no signing invitation. shareToken is the raw token the URL carries, for the cases where your own system stores it.

Asking again returns the same link: it is a permanent property of the document, not a new grant each time.

Warning

The link never expires, anyone who has it can view the document, and the API has no way to withdraw it — a link you have handed out stays valid for as long as the document exists. Treat it as a secret, and use it only where that is acceptable.

A view link is not how you ask somebody to sign. A recipient of a transaction gets their own link, which identifies them and lets them act — see Hand out signing links yourself.

Complete example

Copying a document and publishing a view link to the copy, as a Node.js script. Error handling is minimal for brevity — in production, inspect the error envelope of non-2xx responses.

JavaScript
const BASE_URL = "https://sandbox.circularo.com/api/v1/public"; // your instance's base URL
const API_KEY = "YOUR_API_KEY";
const AUTH_HEADER = { "Authorization": `Bearer ${API_KEY}` };
const documentId = "pXq4NcYBhK9tWdA2mFzR"; // the document to copy

const cloneRes = await fetch(`${BASE_URL}/documents/${documentId}/clone`, { method: "POST", headers: AUTH_HEADER });
if (!cloneRes.ok) throw new Error(`Cloning failed: ${cloneRes.status}`); // error handling kept minimal for brevity

const copy = await cloneRes.json();

const linkRes = await fetch(`${BASE_URL}/documents/${copy.id}/link`, { method: "POST", headers: AUTH_HEADER });
if (!linkRes.ok) throw new Error(`Link failed: ${linkRes.status}`);

console.log(`Copy ${copy.id} can be read at ${(await linkRes.json()).shareUrl}`);

Next steps