{"id":79169,"plugin_id":"plugin_asdk_app_6ad8a84c81cc8191b143b974ae0529ac","kind":"skill","collection_source":"plugin_package","comparison_source":null,"observed_at":"2026-11-03T19:24:48.151Z","digest":"3e2e3ec7cdd632a1c65a02fced014f484bd3bb84f90176ab456eab5687ce5fb4","against":null,"payload":{"description":"Use when writing or changing code that calls SignatureAPI once the signing flow is agreed. Covers creating envelopes, placing signature fields, handling SignatureAPI webhooks, embedding signing, and sending one test envelope. Use it even for a single envelope, and in hosts without a repository. Works in test mode.","included_files":[{"relative_path":"package-lock.json","size_in_bytes":700},{"relative_path":"package.json","size_in_bytes":132},{"relative_path":"references/brownfield-placement.md","size_in_bytes":1744},{"relative_path":"references/ceremonies.md","size_in_bytes":10317},{"relative_path":"references/documents.md","size_in_bytes":2704},{"relative_path":"references/places.md","size_in_bytes":4233},{"relative_path":"references/verification-loop.md","size_in_bytes":14342},{"relative_path":"references/webhooks.md","size_in_bytes":6557},{"relative_path":"scripts/check-setup.mjs","size_in_bytes":1159},{"relative_path":"scripts/complete-ceremony.mjs","size_in_bytes":56755},{"relative_path":"scripts/create-test-envelope.mjs","size_in_bytes":5243},{"relative_path":"scripts/lib/output.mjs","size_in_bytes":3997},{"relative_path":"scripts/make-test-document.mjs","size_in_bytes":2481},{"relative_path":"scripts/openapi-explore.mjs","size_in_bytes":14913},{"relative_path":"scripts/watch-events.mjs","size_in_bytes":3039}],"name":"signatureapi-integrate","skill_md_contents":"---\nname: signatureapi-integrate\ndescription: \"Use when writing or changing code that calls SignatureAPI once the signing flow is agreed. Covers creating envelopes, placing signature fields, handling SignatureAPI webhooks, embedding signing, and sending one test envelope. Use it even for a single envelope, and in hosts without a repository. Works in test mode.\"\ninputs:\n  - name: SIGNATUREAPI_KEY\n    required: true\n---\n\n# Integrate SignatureAPI\n\n## When to reach for something else\n\n- **Deciding who signs, how, and what happens after** belongs to\n  `signatureapi-architecture`.\n- **An integration that already misbehaves** belongs to\n  `signatureapi-diagnose`.\n- **How a SignatureAPI feature behaves**, in prose, belongs to\n  `signatureapi-docs`. Use it before you answer from memory.\n- **Another vendor's webhooks or API** (DocuSign, Dropbox Sign, Adobe Sign)\n  need that vendor's docs. Do not carry their concepts into SignatureAPI.\n- **No SignatureAPI account yet.** Ask whether the user has chosen\n  SignatureAPI. If not, stop.\n\n## Two surfaces\n\n**The application calls the REST API.** The code you deliver uses the\ncodebase's own language and HTTP client against\n`https://api.signatureapi.com/v1`, with the `X-API-Key` header. There is no\nSDK. The app never depends on MCP, the CLI or this skill's scripts.\n\n**You work with MCP, the CLI and the scripts.** This skill works in test\nmode only. Test keys start with `key_test_`.\n\n- **MCP** (`https://mcp.signatureapi.com/mcp`) inspects and exercises the\n  API. MCP mode is per call: pass `mode: \"test\"` explicitly when creating\n  and listing. `whoami.modes.live` is permission to use live mode, not the\n  current mode. Reads by id follow the resource's mode. Never pass `live`\n  without the user's explicit intent. Check the mode a create returns; if an\n  unintended live envelope was created, stop and tell the user. Its tools,\n  by job:\n  - Documents: `upload_file` or `mint_upload_url`, `inspect_upload`.\n  - Envelopes: `create_envelope`, `get_envelope` (takes `envelope_id`),\n    `list_envelopes`, `cancel_envelope`, `delete_envelope` (final status\n    only; cancel first).\n  - Recipients: `resend_request`, `replace_recipient`, `create_ceremony`.\n  - Watching: `list_events`, `get_deliverables`, `list_emails`,\n    `get_email`.\n  - Session: `whoami`. Call it only when the user asks which account is\n    connected or a requested live action needs an access check.\n  - Webhooks: `list_webhooks`, `create_webhook`, `update_webhook`,\n    `list_webhook_attempts`, `delete_webhook`.\n  - Docs: `search_documentation`. Reach it through `signatureapi-docs`,\n    which decides when a keyword search helps.\n- **The CLI** (`npx --yes signatureapi <command>`) handles secrets and\n  local ports when you have a shell. `init` writes the test key to the\n  env file. `listen` tunnels test webhooks to a local handler and writes\n  their signing secret. `trigger <event type>` sends one example event.\n  `api-keys list --mode test` shows key metadata. `whoami` names the\n  account the CLI acts for. No command prints a secret. Never run a CLI command with\n  `--mode live`.\n- **The scripts** here read the contract and drive a test envelope. See\n  Scripts below.\n\nA missing MCP tool does not prove a REST operation exists. Confirm it with\n`node scripts/openapi-explore.mjs operation <method> <path>` first. If that\nfails, stop and report the gap at\nhttps://github.com/signatureapi/skills/issues/new.\n\nDo not collect government IDs, health information, payment-card data,\nbiometric verification, passwords, or authentication codes through the\nplugin. This applies to documents, metadata, template values and free text.\nUse synthetic test data. Custom authentication evidence stays in the user's\napplication; plugin inputs accept only non-secret audit references and\ntimestamps. Never ask the user to paste credentials into chat.\n\n## Know your host\n\n- **A shell:** use the CLI and the scripts. **No shell:** use MCP for every\n  step, and the dashboard for credentials.\n- **Upload tool:** your client lists `upload_file` (takes a host-provided\n  file reference), `mint_upload_url` (returns a URL to send the bytes to),\n  or both. With both, use `mint_upload_url` for local files with a shell\n  and `upload_file` only for host-provided file references. Never invent a\n  file reference.\n- **No filesystem:** do not ask for the key. MCP is already authenticated.\n- **No repository** (a chat host such as ChatGPT): design with\n  `signatureapi-architecture` and prove the flow with MCP in test mode.\n  Hand over the design and the proven request bodies. Say that the code is\n  written in a coding environment with the repository open.\n\n## The spec decides facts\n\n`https://spec.signatureapi.com/openapi.yaml` is the source of truth for\nfield names, enum values, events, paths and limits. Where this skill and\nthe spec disagree, the spec wins. Query it before writing a request body or\na handler; the docs pages are too large for this.\n\n    node scripts/openapi-explore.mjs operations [filter]\n    node scripts/openapi-explore.mjs operation post /envelopes\n    node scripts/openapi-explore.mjs schema Place.PlaceInput\n    node scripts/openapi-explore.mjs webhooks\n    node scripts/openapi-explore.mjs check-request get '/envelopes/<id>/deliverables?limit=20'\n\n`check-request` validates a request locally and sends nothing. For prose,\nuse `signatureapi-docs`.\n\n## Setup\n\nThe key goes into the project's gitignored env file without passing through\nthe chat. No MCP tool returns a credential.\n\n1. For MCP-only work, OAuth already authenticates calls; no API key is\n   needed. For application code or the bundled REST scripts, set up the key:\n2. **With a shell**, run `npx --yes signatureapi init` from the\n   application directory, in a background shell. It prints a verification\n   URL and a code, then waits. Give both to the user to approve. It then\n   writes the test key as `SIGNATUREAPI_KEY` to `.env.local` (Next.js) or\n   `.env`. Use `--env-path` and `--var` to match the project. Its result\n   names the account as `account.id`. With the MCP connected, compare it\n   with `whoami`'s `account.id`. If they differ, the CLI and the MCP act\n   for different organizations: stop and ask the user which one to use,\n   then run `npx --yes signatureapi logout` and `login` to switch.\n   **Without a shell**, ask the user to copy the test key from\n   `https://dashboard.signatureapi.com/settings/api-keys` into the env\n   file. Name the file and the variable.\n3. Confirm the env file is gitignored. Then install the scripts' one\n   dependency and check the setup from this skill's directory:\n\n        npm i\n        node --env-file=<project env file> scripts/check-setup.mjs\n\nPass the env file with `--env-file` to every script. Never `cat`, `source`\nor `export` it, never ask the user to paste the key, and never put the key\nin code, a commit, a log or a command argument. Leave\n`SIGNATUREAPI_BASE_URL` and `SIGNATUREAPI_SPEC_URL` unset.\n\n## Start from the design\n\nClassify the request first.\n\n- **A narrow change** (one more place, one more event, a bug): go to Orient\n  and Build.\n- **One new signing flow, or a change to who signs, how they authenticate\n  or who receives email:** get a design brief approved in chat first.\n  `signatureapi-architecture` writes it: a few plain lines, one yes. When a\n  design document exists, update it instead.\n- **A platform-shaped product**, or the user asks for a document. Platform\n  means users send their own documents, draw their own fields or send in\n  their own name; \"a platform like X\". The approved design document must\n  exist at `docs/signatureapi-integration.md`, or that file must point to\n  it. If it does not, run `signatureapi-architecture` first.\n\nBuild from what the user approved. Where it is silent on a technical\nchoice, take the default from the architecture skill's decision matrix and\nsay so. Keep the user's names for their concepts; SignatureAPI terms belong\nat the API boundary. The product shapes a design may name are in\n`../signatureapi-architecture/references/product-shapes.md`.\n\n## Orient in this codebase first\n\nFind where signing belongs before writing anything:\n`references/brownfield-placement.md`.\n\n## Build\n\nSteps 1–3 prove the flow against the test API. Step 4 is the deliverable.\n\n1. **Get a document URL.** For a throwaway PDF, run\n   `node scripts/make-test-document.mjs`. To upload a file while you work,\n   use your client's upload tool, or `POST /uploads` with the raw bytes and\n   a `Content-Type` header; each returns a temporary `url`. Accepted types,\n   the size limit and the URL's lifetime are in\n   `node scripts/openapi-explore.mjs operation post /uploads`. For the app's own files, read\n   `references/documents.md` first; most failed envelopes come from the\n   source file. List the document's bindings and reconcile each one with a\n   place or template value, as `references/places.md` describes. Use\n   `inspect_upload` to confirm what the service detected.\n2. **Create the envelope.** Start from\n   `node scripts/create-test-envelope.mjs --dry-run` and adapt it. Every\n   place's `recipient_key` must match a recipient's `key`. The script\n   defaults to `custom` authentication so verification needs no email;\n   `--auth` takes `email_link`, `email_code` or an ordered list:\n   `--auth email_link,email_code` keeps SignatureAPI emailing the link and\n   adds an emailed code.\n   `references/verification-loop.md` explains which method delivers the\n   link. Read `references/ceremonies.md` when the flow delivers links\n   itself, embeds signing or has several recipients. Keep test titles and\n   messages plain: an account may reject URL-, phone- or date-like text\n   there. If the design sets `branding.logo`, use the `url` of a permanent\n   PNG upload in the same account; the API rejects any other URL,\n   including a temporary upload. Upload the PNG with `POST /uploads`, then\n   call `POST /uploads/{uploadId}/store` with a unique `key`. Or ask the\n   user to upload it in the Dashboard Library and give you its URL.\n   Re-run without `--dry-run` to create it. With MCP, pass `mode: \"test\"`\n   to `create_envelope`.\n3. **Handle events.** Handle `envelope.completed` for status and\n   `deliverable.generated` to fetch the signed file.\n   **With a shell**, start the app's handler, then in a background shell:\n\n        npx --yes signatureapi listen --forward-to http://127.0.0.1:<port>/<path>\n\n   Wait for it to report ready. It writes `SIGNATUREAPI_WEBHOOK_ID` and\n   `SIGNATUREAPI_WEBHOOK_SECRET` to the env file. Send an example with\n   `npx --yes signatureapi trigger envelope.completed` and check the\n   handler's own output for a 2xx. Stop the listener when done; that\n   disables the endpoint.\n   **Without a shell**, or for an endpoint already hosted, register it\n   with `create_webhook`. The user copies the signing secret from\n   `signing_secret_dashboard_url`. There is no MCP sample-delivery tool:\n   create a synthetic test envelope to generate real test events, then\n   check delivery with `list_webhook_attempts`.\n   `references/webhooks.md` has the verification code and the handler rules.\n4. **Write it into the application**, using the codebase's conventions.\n   Put the `POST /envelopes` call where the domain action happens. Mount\n   the webhook handler on the app's inbound-HTTP path; it verifies the\n   signature first. Persist the envelope id on the domain record. Read the key from\n   the app's configuration. Re-decide authentication for real recipients\n   (`references/verification-loop.md`).\n\n## Verify\n\nThe flow is proven when the test envelope reaches `completed`, the events\nexist, and the signed file's bytes pass the app's own retrieval and storage\npath.\n\n- **Branch A (default):** give the user the ceremony link and wait for them\n  to sign. With `custom` authentication the link is in the create response\n  (`recipients[].ceremony.url`). With `email_link` it is only in the test\n  email: `list_emails`, then `get_email`.\n- **Branch B:** when the user asks you to sign, run\n  `node --env-file=<project env file> scripts/complete-ceremony.mjs --envelope <id>`.\n  It needs Playwright (`npm install --save-dev playwright && npx playwright install chromium`),\n  handles signature places only, and refuses a live key.\n\nThen call `list_events` with the `envelope_id` and `wait_seconds: 20`. On\n`timed_out`, call it again; do not sleep and poll. Fetch the file with\n`get_deliverables`. Without MCP, use `scripts/watch-events.mjs`. Details:\n`references/verification-loop.md`.\n\n## Scripts\n\nRun them from this skill's directory with\n`node --env-file=<project env file> scripts/<name>`. They print JSON;\nfailures carry `code`, `message` and `next`.\n\n| Script | Does |\n| --- | --- |\n| `check-setup.mjs` | Checks the key, its mode and reachability |\n| `openapi-explore.mjs` | Reads the contract (Markdown; `--json` for programs) |\n| `make-test-document.mjs` | Uploads a throwaway test PDF |\n| `create-test-envelope.mjs` | Prints (`--dry-run`) or creates a minimum test envelope |\n| `watch-events.mjs` | REST fallback for `list_events` (`--once` for one check) |\n| `complete-ceremony.mjs` | Branch B browser walk; test mode only (`--embedded redirect` or `message` also checks the event) |\n\n## References\n\n- `references/brownfield-placement.md` — where signing belongs in an existing codebase\n- `references/documents.md` — file sources, DOCX and PDF traps, generated PDFs\n- `references/places.md` — how places bind to a document\n- `references/ceremonies.md` — link lifecycle, embedding, recipients after creation, live-mode email\n- `references/webhooks.md` — registering an endpoint, verification and the handler shape\n- `references/verification-loop.md` — both verification branches in full\n\n## Vocabulary\n\nAn **envelope** holds **documents** and **recipients**. **Places** are\nregions on a document bound to a recipient. Each recipient signs through a\n**ceremony**. Completion produces a **deliverable**: the signed documents\nplus an audit log.\n"},"changes":[],"summary":"First saved snapshot. No earlier version is available for comparison.","summary_kind":"deterministic","summary_metadata":{}}