sign-free.openapps.xyz

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.
Owned app · rev 528326727848
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.
← All files
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
5283267278 · 5 hours ago
Bounded source sync
15f0fa2e27 · 1 day ago
Bounded source sync
d3aa1ca65b · 1 day ago
Bounded source sync
8e2ca0b773 · 1 day ago
Bounded source sync
5cfa84715c · 1 day ago
Bounded source sync
c849e7b286 · 1 day ago
Bounded source sync
68c1cabe03 · 1 day ago
Bounded source sync
62ae8944f0 · 1 day ago
Bounded source sync
7ed54e7381 · 1 day ago