{"service":"Pro Sign AI","summary":"API-first electronic signature service. An AI agent can register for a person in seconds: send the person's name, email and the permissions you need; you get your token and its ID back immediately. The token does nothing until the person approves and signs on a one-page form in their browser (no typing); then it goes live with exactly the approved permissions. Then you send PDFs for legally valid e-signature, get webhooks, and download sealed results.","register":{"step1":{"method":"POST","url":"https://sign.prodevgroup.com/api/v1/agent-access/requests","auth":"none","body":{"email":"the person you act for, who will own the key (required)","name":"the person's name (required), used in the greeting and for their account","organizationName":"their company (optional, used if they have no account yet)","agentName":"how you, the assistant, introduce yourself; the person sees this in the email and on the approval page, e.g. \"Lori (Pro Building assistant)\" (optional; default \"<Name>'s AI assistant\")","purpose":"one sentence on why (optional)","requestedScopes":["documents:read","documents:write","documents:send","webhooks:manage"],"note":"your own wording to the person (optional)","validForHours":"optional: ask for a TEMPORARY token that stops on its own this many hours after approval (1 to 168, one week). Use it when you cannot store a secret safely (chat transcript, no credential store). \"temporary\": true alone means 24 hours."},"response":"apiKey (your token, shown once), tokenId (how you refer to it later), tokenStatus PENDING, and pollUrl (keep it; it contains a secret)","example":"curl -X POST https://sign.prodevgroup.com/api/v1/agent-access/requests -H 'content-type: application/json' -d '{\"email\":\"jane@example.com\",\"name\":\"Jane Doe\",\"agentName\":\"Jane\\u2019s assistant\",\"purpose\":\"Send contracts for signature\",\"requestedScopes\":[\"documents:read\",\"documents:write\",\"documents:send\"]}'"},"step2":"The person gets an email with one page: their name (editable), a permission table (Permission | Asked | Approve | Deny) prefilled from your request, the electronic-signing consent and a signature pad. They tap Approve and sign. Nothing is granted until then.","step3":"Until then every call with your token answers 403 token_pending_approval. Poll pollUrl every 30 to 60 seconds (tokenStatus becomes ACTIVE, status APPROVED), or simply retry; DECLINED or EXPIRED (7 days) means no.","step4":"Once approved the same token is live with exactly the permissions the person approved (they may approve fewer than you asked). Nothing to pick up.","step5":"Use the token as \"Authorization: Bearer psk_live_...\" on https://sign.prodevgroup.com/api/v1 or as the bearer on the MCP endpoint https://sign.prodevgroup.com/mcp. Keep the tokenId: it is how you refer to the token later (never send the token itself).","changePermissions":"POST https://sign.prodevgroup.com/api/v1/agent-access/changes with your key and the new requestedScopes; the person re-approves and re-signs; your key's permissions change in place.","actions":{"new_account":"first token for a person who has no account yet; token returned now, live after approve + sign","new_token":"another token on an existing account, for a different agent or application; token returned now, live after approve + sign","rotate_token":"fresh token with the same permissions returned now; one-tap confirm makes it live and stops the old one; needs tokenId","update_permissions":"change what a token may do; needs tokenId and requestedScopes (approve + sign)","remove_tokens":"revoke tokens; tokenIds, or omit to let the person pick (one-tap confirm)","create_company":"create a company with the person as owner; needs companyName (+ optional companyDetails). You get the company code (co_...) at once; the company and your company-bound token go live when the owner signs","join_company":"join an existing company for the person; needs companyId. The person signs for your company-bound token, and a company admin approves the membership with one tap; the token goes live when both are done","transfer_company":"the company owner signs over control to another active member; needs companyId and newOwnerEmail","companies":"A person has a personal workspace and can belong to any number of companies with the same email. Every documents/templates/webhooks call takes companyId (query or body) to run in that company; without it the call is personal. Company templates and documents are visible to company admins; personal ones are not. If the person is not an active member you get 403 not_a_member; an unknown code gives 404 no_company. GET /me lists the workspaces.","note":"Every action emails the person a one-page form. Default action is new_account for an unknown email, otherwise new_token."},"temporaryKeys":"If your key would end up in a chat transcript or you have nowhere safe to keep it, ask for a temporary one: add \"validForHours\": 24 (any whole number from 1 to 168) to a new_account or new_token request. The token works for exactly that long after the person approves, then stops on its own (calls answer 401 token_expired). Ask again as often as you like: the first temporary token needs the signed authorization like any other; every later one is a one-tap approval email with no signature, so it costs the person almost nothing. The response and pollUrl carry temporary, validForHours and tokenExpiresAt."},"permissions":[{"scope":"documents:read","title":"See documents and their status","description":"List documents, read who has signed, download completed files, audit trails and certificates."},{"scope":"documents:write","title":"Prepare documents","description":"Upload PDFs, add signers and fields, edit drafts, delete drafts."},{"scope":"documents:send","title":"Send for signature","description":"Send documents to people in your name, send reminders, issue signing links, void documents."},{"scope":"templates:read","title":"Use templates","description":"See and use your saved templates."},{"scope":"templates:write","title":"Manage templates","description":"Create and delete templates."},{"scope":"webhooks:manage","title":"Receive event notifications","description":"Register web addresses that get notified when documents are viewed, signed or completed."},{"scope":"admin","title":"Full control","description":"Everything above, plus managing members, other people's keys and organization settings."}],"afterRegistering":{"docs":"https://sign.prodevgroup.com/api/v1/docs","openapi":"https://sign.prodevgroup.com/api/v1/openapi.json","mcp":"https://sign.prodevgroup.com/mcp","sendingTips":["No vision and a PDF with no signature lines (an invoice, a letter)? Add \"signaturePage\" to POST /documents: you write the title and the statement, the server appends a page with a block per signer (signature line, date line, printed name, optional title) and places the fields itself; the response carries signaturePageText so you can check it. Example: {\"enabled\":true,\"title\":\"Acknowledgment of Receipt\",\"statement\":\"By signing below, I acknowledge that I received and reviewed Final Invoice PB-2026-KEN-FINAL dated October 12, 2026.\",\"blocks\":[{\"recipient\":1,\"label\":\"Homeowner\",\"printedName\":\"Jason Kendrick\",\"fields\":[\"signature\",\"date\"],\"align\":\"left\"},{\"recipient\":2,\"label\":\"Homeowner\",\"printedName\":\"Christina Kendrick\"}]}.","Put anchor tags in your PDF ({{signature:1}}, {{date:1}}, {{name:1}}, {{text:1:Policy number}}, {{checkbox:1}}) and set useAnchors:true; no coordinates needed. Add a last part left, center or right to align inside the box ({{signature:1:right}}); fields by coordinates take \"align\".","Several PDFs for the same people? POST /packets with a documents list (each with its own recipients and fields). Every signer gets one link for all of them, consents once, sees \"1/3 complete\", and moves to the next document automatically. orderLocked:true forces the order; the read-only link covers the whole packet.","Something to show but not sign (an invoice, an exhibit)? Add it as an attachment: in a packet a document with \"attachment\": true, or on POST /documents an \"attachments\" list (that turns the request into a packet behind the scenes; the response is still the document, with packet.id). Signers must open it; \"acknowledge\": \"sign\" or \"initial\" appends a receipt sheet instead. By default a packet with an attachment ends with a sealed Packet Acknowledgment: one signature per signer, every document listed with its SHA-256, always the last step. \"acknowledgment\": true/false overrides; GET /settings and PATCH /settings hold the workspace rule (always, attachments, never). When a packet completes, each person gets one \"Packet completed\" email (no per-document emails): the whole packet as one sealed PDF (every document followed by its certificate, then the packet audit; GET /packets/{id}/file, attached when small enough), a status page with per-document downloads, and their read link for an AI assistant. A review-only attachment also ends up sealed and timestamped, with a review record of who opened it. \"signedNotices\" in /settings (standalone by default) says whether the sender gets a \"Signed by X\" email per signature outside packets.","POST /documents/{id}/recipients/{rid}/link returns a signing link, a read-only link the signer can hand to their own AI, and a ready-to-send message you can personalize with note or messageTemplate.","Register a webhook to be told when a document is viewed, signed, declined or completed; or poll GET /documents/{id}.","GET /documents/{id}/text returns the document text so you can read it without vision."]},"signatureSpots":"Place fields without vision. GET /documents/{id}/signature-spots scans the PDF for signature, initials, date, printed-name and title lines (labels such as SIGNATURE, SIGN HERE, BY:, DATE, INITIALS, PRINTED NAME, TITLE; drawn lines; runs of underscores) and returns a numbered list, each with a plain-English description such as \"Signature line above 'Christina Kendrick / PRINTED NAME' in the block labeled 'Homeowner'\", the paired date spot, and a ready box above the line (26pt for a signature, 18pt for a date). Lines that already carry printed text are skipped. Give each recipient fields like [{\"spot\": 1}, {\"spot\": 2}] instead of coordinates; the server sizes them. Fastest path: POST /documents with \"detectSpots\": true (it returns signatureSpots and never sends), choose spots, PATCH /documents/{id} with recipients, then POST /documents/{id}/send. Spots work in templates too ({\"spot\": n, \"roleOrder\": r}).","signaturePage":"Generated signature page, for any PDF and no coordinates: \"signaturePage\": { \"enabled\": true, \"title\": \"Acknowledgment of Receipt\" (default \"Signatures\"), \"statement\": \"...plain text, blank lines become paragraphs, max 3000 characters...\", \"blocks\": [ { \"recipient\": 1, \"label\": \"Homeowner\", \"printedName\": \"Jason Kendrick\", \"title\": null, \"fields\": [\"signature\",\"date\"], \"align\": \"left\" }, ... ], \"layout\": \"stacked\" | \"two-column\" } on POST /documents, on each document of POST /packets, and on PATCH /documents/{id} (DRAFT; enabled:false removes it). \"recipient\" is the recipient order number; allowed fields: signature, initials, date, name, title, text:<label>, checkbox:<label> (default signature and date). The page matches the last page size and the certificate style: title, statement, a reference line (document title, original page count, first 16 characters of the upload SHA-256, \"This page is part of the document above.\"), then the blocks with captioned lines; long lists continue on a second page. Fields sit on the lines like spots do (full line length, 26 pt signature box, 22 pt initials, 18 pt date and text; align honored). A recipient with a block needs no other fields; a signer with no fields anywhere or a block for an unknown recipient answers 400 with the problem named. The response carries signaturePageText (a plain-text rendering of the page) and the total pageCount, fields appear under each recipient as usual, originalSha256 stays the upload hash and assembledSha256 is the PDF with the page; the certificate shows both. Invoice example: POST /documents {\"title\":\"Final Invoice PB-2026-KEN-FINAL\",\"fileBase64\":\"...\",\"recipients\":[{\"name\":\"Jason Kendrick\",\"email\":\"jason@example.com\",\"order\":1},{\"name\":\"Christina Kendrick\",\"email\":\"christina@example.com\",\"order\":2}],\"signaturePage\":{\"enabled\":true,\"title\":\"Acknowledgment of Receipt\",\"statement\":\"By signing below, I acknowledge that I received and reviewed Final Invoice PB-2026-KEN-FINAL dated October 12, 2026.\",\"blocks\":[{\"recipient\":1,\"label\":\"Homeowner\",\"printedName\":\"Jason Kendrick\",\"fields\":[\"signature\",\"date\"],\"align\":\"left\"},{\"recipient\":2,\"label\":\"Homeowner\",\"printedName\":\"Christina Kendrick\",\"fields\":[\"signature\",\"date\"]}]},\"send\":true}.","options":"Per field: \"align\" left | center | right (default center for signatures and initials, left for text; anchors: {{signature:1:right}}). Per document: \"dateFormat\" (tokens YYYY YY MMMM MMM MM M DD D; default MM/DD/YYYY) and \"timeZone\" (IANA, default America/Chicago) decide how DATE fields print; the certificate and audit trail stay in UTC. Every recipient object in a response carries its own \"fields\" list as well as the document-level list.","testMode":"\"testMode\": true on POST /documents (or /packets) makes a safe dry run: every email goes to the API key owner only, with [TEST] in the subject and the real recipient named, you may list yourself for every signer role (the duplicate-signer rule is off), the sealed PDF and the certificate carry a TEST mark on every page, and the document shows testMode: true in lists. Use it to sign each role yourself before sending a real document.","trust":"Every sealed PDF carries an RFC 3161 trusted timestamp from a public authority (DigiCert, then Sectigo, then FreeTSA) over the seal signature, and the certificate names the authority and time of a second timestamp over the stamped document; GET /documents/{id} shows timestamp.status (done, pending, none) and the audit trail has \"timestamped\" events. If no authority answers, the document is still sealed, \"timestamp unavailable\" is recorded, and the worker retries. The electronic-signing disclosure is versioned: each signer's consent stores the version, and the exact text is at /legal/esign-disclosure/<version> (listed at /legal/esign-disclosure). While the active version is a draft, non-test sends answer 409 disclosure_draft. Signers can also leave the sender a note from the signing page without signing or declining (audit action note_left, emailed to the owner); a decline carries the signer's reason the same way. A signing link that has been used stays alive as a status page for as long as the record exists (who has signed, who is pending, completion time) with the current or sealed PDF at <link>/pdf and, once completed, the certificate at <link>/certificate; the read-only link for the signer's own AI keeps answering too (/read/<token> gains a Parties section, /read/<token>/certificate, and certificateUrl in /json). Only unused links that expired, and links the sender revoked, stop answering.","packets":"Several documents in one request: POST /packets with {\"title\",\"orderLocked\",\"documents\":[{\"title\",\"fileBase64\" or \"templateId\",\"recipients\":[...],\"useAnchors\"}, ...],\"send\":true}. Each document keeps its own PDF, recipients, fields, signing order, seal and certificate. Each signer gets ONE email with ONE link that opens every document they are on; they agree to sign electronically once (it covers all of them), see a progress bar such as \"1/3 complete\" with numbered tabs, and are taken to the next document automatically after each signature. orderLocked:true means they must sign in the order listed (the page shows a single \"Proceed\" button); false means they pick from a numbered list in any order. The read-only link for an AI assistant covers all documents of the packet (/read/<token> lists them; /read/<token>/pdf?doc=2 is the second PDF). Signing order is packet-wide: \"signingOrder\": \"SEQUENTIAL\" sends the whole packet to the first signer group, and only when they have finished every document of theirs does it go to the next group; groups come from \"signers\": [{\"email\",\"order\"}] (same number = at the same time, e.g. A first, then B and C together) or, when omitted, from each signer's lowest recipient order across the documents. PARALLEL (default) opens the packet to everyone at once. A document's own signingOrder still applies inside that document. POST /packets/{id}/signers/{email}/link gives you a packet link and a ready-to-send message; GET /packets/{id} shows per-document and per-signer progress; /remind and /void work for the whole packet. The same signer may be on only some of the documents. Attachments: a document with \"attachment\": true carries no recipients or fields; everyone on the packet sees it, each signer must open it before the last step (the page records the review with time, IP and device), and it concludes together with the packet. \"acknowledge\": \"sign\" or \"initial\" instead appends an \"Acknowledgment of Receipt\" sheet with a block per signer, and the attachment becomes a document they sign or initial. Packet Acknowledgment: when on (packet \"acknowledgment\": true/false, else the workspace rule: always, attachments (default), never via GET/PATCH /settings), every signer gets one more document, kind PACKET_ACKNOWLEDGMENT, created at send time after the last position: it lists every document they are on with page count, part (signed, initialed, provided for review) and SHA-256 of the file as sent, and takes one signature. It is always the last step: the API answers 409 packet_order until the signer has signed or initialed everything else and opened every attachment. Word it yourself by passing an object instead of true: \"acknowledgment\": {\"title\": \"Close-out Acknowledgment\", \"intro\": \"...\", \"statement\": \"By signing, {{signer}} confirms receipt of all {{count}} documents of {{packet}} from {{sender}}.\"} (parts left out keep the service wording; the sheet notes which parts are yours). An attachment's receipt sheet takes \"acknowledgeTitle\" and \"acknowledgeStatement\" the same way (placeholders {{title}}, {{pages}}, {{sender}}, {{packet}}). Document kinds appear as \"kind\" on every document view.","legal":"Signatures follow the ESIGN Act and Alabama UETA: consumer consent, adopted signature, intent statement, full audit trail and a sealed PDF with a certificate of completion."}