Source
This app’s code and revision history are public. Download a copy or explore the files below.
Public
The app’s code and revision history are public.
Run it yourself
Take the whole tree and run it on your own machine. The download needs no account. Cloning needs a sign-in.
Download .zip
bounded clone 1da91c033c738ab74538d13d
A copy you download is not bounded. The guarantees this app runs under - declared egress, proven invariants, writes that fail closed - live in the runtime serving this page, not in the files. What you get is auditable source you can read and run, with no runtime guarantees attached.
public/openapi.json
{
"openapi": "3.1.0",
"info": {
"title": "Sign by OpenApps API",
"version": "1.0.0",
"summary": "Free e-signatures for AI assistants. No account and no API key.",
"description": "Create a document from text, get one private signing link per signer, then check who has opened and signed it. Sign renders the text into a PDF with a signature block (signature, full name, date) for each signer. To send an existing PDF, the person uploads it in the web app at https://sign-free.openapps.xyz/. Errors are JSON: {\"error\": \"<a sentence that says what to change>\"}.",
"license": { "name": "Free to use" }
},
"servers": [{ "url": "https://functions.bounded.sh/apps/1da91c033c738ab74538d13d/api" }],
"externalDocs": { "description": "Guide for assistants", "url": "https://sign-free.openapps.xyz/llms.txt" },
"paths": {
"/": {
"get": {
"operationId": "listRoutes",
"summary": "List the routes",
"responses": {
"200": {
"description": "The API's name, routes and docs link.",
"content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string" }, "about": { "type": "string" }, "docs": { "type": "string" }, "routes": { "type": "array", "items": { "type": "string" } } } } } }
}
}
}
},
"/documents": {
"post": {
"operationId": "createDocument",
"summary": "Send a text document for signature",
"description": "Creates the document already sent: each signer can sign from their own signUrl right away. Give each signer only their own link. Give the person you work for the adminUrl.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/CreateDocument" },
"example": {
"title": "Freelance design agreement",
"text": "# Freelance design agreement\n\nThis agreement is between Sam Lee and Alex Kim.\n\n## Payment\n\nAlex will pay $1,200 on delivery.",
"signers": [{ "name": "Sam Lee", "email": "sam@example.com" }, { "name": "Alex Kim" }],
"message": "Here is the agreement we discussed."
}
}
}
},
"responses": {
"201": {
"description": "Created and sent.",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/Created" },
"example": {
"documentId": "rAmsKgtmnUVDKmVCVhN6",
"title": "Freelance design agreement",
"status": "sent",
"adminUrl": "https://sign-free.openapps.xyz/d/rAmsKgtmnUVDKmVCVhN6#k=OWNER_KEY",
"ownerKey": "OWNER_KEY",
"signers": [
{ "name": "Sam Lee", "email": "sam@example.com", "signUrl": "https://sign-free.openapps.xyz/s/rAmsKgtmnUVDKmVCVhN6/kwFaeGbUAF#t=SIGNER_TOKEN" },
{ "name": "Alex Kim", "email": null, "signUrl": "https://sign-free.openapps.xyz/s/rAmsKgtmnUVDKmVCVhN6/jekiPLbPZo#t=SIGNER_TOKEN" }
],
"next": "Send each signer their own signUrl (it is private to them). Give the person you work for the adminUrl: it shows who has signed and the signed PDF. Check status with GET /documents/:id and the ownerKey."
}
}
}
},
"400": { "$ref": "#/components/responses/Error" }
}
}
},
"/documents/{documentId}": {
"get": {
"operationId": "getDocument",
"summary": "Check who has opened and signed",
"parameters": [{ "$ref": "#/components/parameters/DocumentId" }, { "$ref": "#/components/parameters/OwnerKey" }],
"responses": {
"200": {
"description": "The document's status, with each signer's link and times.",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/Status" },
"example": {
"documentId": "rAmsKgtmnUVDKmVCVhN6",
"title": "Freelance design agreement",
"status": "sent",
"adminUrl": "https://sign-free.openapps.xyz/d/rAmsKgtmnUVDKmVCVhN6#k=OWNER_KEY",
"fingerprint": "sha256:1fac01c31f5db045...",
"signers": [
{ "name": "Sam Lee", "email": "sam@example.com", "signUrl": "https://sign-free.openapps.xyz/s/rAmsKgtmnUVDKmVCVhN6/kwFaeGbUAF#t=SIGNER_TOKEN", "viewedAt": "2026-10-19T22:43:10.000Z", "signedAt": "2026-10-19T22:43:40.000Z" },
{ "name": "Alex Kim", "email": null, "signUrl": "https://sign-free.openapps.xyz/s/rAmsKgtmnUVDKmVCVhN6/jekiPLbPZo#t=SIGNER_TOKEN", "viewedAt": null, "signedAt": null }
],
"note": "Send each signer their own signUrl. The signed PDF is ready once everyone has signed."
}
}
}
},
"401": { "$ref": "#/components/responses/Error" },
"403": { "$ref": "#/components/responses/Error" },
"404": { "$ref": "#/components/responses/Error" }
}
}
},
"/documents/{documentId}/void": {
"post": {
"operationId": "voidDocument",
"summary": "Stop collecting signatures",
"description": "The signing links stop working. Signatures already made stay on the record. Only a sent document can be voided, once.",
"parameters": [{ "$ref": "#/components/parameters/DocumentId" }, { "$ref": "#/components/parameters/OwnerKey" }],
"responses": {
"200": { "description": "Voided. Returns the status with status \"voided\".", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Status" } } } },
"401": { "$ref": "#/components/responses/Error" },
"403": { "$ref": "#/components/responses/Error" },
"404": { "$ref": "#/components/responses/Error" },
"409": { "$ref": "#/components/responses/Error" }
}
}
}
},
"components": {
"parameters": {
"DocumentId": { "name": "documentId", "in": "path", "required": true, "description": "The documentId returned when the document was created.", "schema": { "type": "string", "pattern": "^[A-Za-z0-9]{8,32}$" } },
"OwnerKey": { "name": "x-owner-key", "in": "header", "required": true, "description": "The ownerKey returned when the document was created. A ?key= query parameter also works.", "schema": { "type": "string" } }
},
"responses": {
"Error": {
"description": "What went wrong, as a sentence that says what to change.",
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "error": "That owner key does not match this document." } } }
}
},
"schemas": {
"CreateDocument": {
"type": "object",
"required": ["title", "text", "signers"],
"properties": {
"title": { "type": "string", "minLength": 1, "maxLength": 200 },
"text": { "type": "string", "minLength": 20, "maxLength": 100000, "description": "The full document as plain text or simple Markdown: # and ## headings, blank lines between paragraphs, - or 1. list items, **bold** in a paragraph is printed plain." },
"signers": { "type": "array", "minItems": 1, "maxItems": 10, "items": { "$ref": "#/components/schemas/SignerInput" } },
"message": { "type": "string", "maxLength": 2000, "description": "Shown to every signer above the document." }
}
},
"SignerInput": {
"type": "object",
"required": ["name"],
"properties": {
"name": { "type": "string", "minLength": 1, "maxLength": 80 },
"email": { "type": "string", "format": "email", "maxLength": 200, "description": "Printed on the document and certificate. Sign does not send email." }
}
},
"Created": {
"type": "object",
"properties": {
"documentId": { "type": "string" },
"title": { "type": "string" },
"status": { "type": "string", "const": "sent" },
"adminUrl": { "type": "string", "description": "The owner's private page: who opened and signed, and the signed PDF once everyone has signed." },
"ownerKey": { "type": "string", "description": "Send it as x-owner-key to check status or void." },
"signers": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string" }, "email": { "type": ["string", "null"] }, "signUrl": { "type": "string", "description": "Private to this signer: anyone with it can sign as them." } } } },
"next": { "type": "string" }
}
},
"Status": {
"type": "object",
"properties": {
"documentId": { "type": "string" },
"title": { "type": "string" },
"status": { "type": "string", "enum": ["draft", "sent", "completed", "voided"], "description": "completed means every signer has signed." },
"adminUrl": { "type": "string" },
"fingerprint": { "type": "string", "description": "sha256: followed by the SHA-256 of the original document (for text documents, of the text)." },
"signers": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": { "type": "string" },
"email": { "type": ["string", "null"] },
"signUrl": { "type": ["string", "null"] },
"viewedAt": { "type": ["string", "null"], "format": "date-time" },
"signedAt": { "type": ["string", "null"], "format": "date-time" }
}
}
},
"note": { "type": "string" }
}
},
"Error": { "type": "object", "required": ["error"], "properties": { "error": { "type": "string" } } }
}
}
}
Change history
Quality pass: phone signing, edit signers, copy to send again
Bounded source sync
Bounded source sync
Bounded source sync
Bounded source sync
Bounded source sync
Bounded source sync
Bounded source sync
Bounded source sync