Skip to the content

Documentation

Search and payments

Search the workspace, list the payments taken while signing, and refund them in full or in part.

These calls do what the app's own screens do: the search box and the Payments tab of Billing. Each one calls the same code as the screen, so the API and the app always give the same answer.

You want to Call Scope
Find documents, templates and people GET /api/v1/search?q=… documents:read
List payments taken while signing GET /api/v1/payments documents:read
Refund a payment, in full or in part POST /api/v1/payments/{id}/refund documents:write

A key without the scope gets 401, the same answer as a wrong key. Another workspace's document or payment is 404: a key never learns that it exists.

q is the words to look for. per is how many of each kind come back (1 to 20, default 6). The answer is grouped into documents, templates and people, best match first.

import { Docustay } from "@docustay2026/sdk";
const docustay = new Docustay(process.env.DOCUSTAY_API_KEY);
const r = await docustay.search("Deposit", { per: 5 });
for (const d of r.groups.documents) console.log(d.id, d.state, d.title);

Payments

A payment box on a document takes a fixed amount while the person signs. GET /api/v1/payments lists them newest first, with this month's figures in month. Each payment has its status:

Status Means
paid Stripe took the money
waiting signed, and the signature is kept while they pay (for up to 7 days)
started they opened the payment and did not finish it
refunded / partially_refunded some or all of it was given back
disputed the payer's bank opened a dispute; answer it in Stripe

In month, stripeFee is Stripe's own fees on this month's payments, and stripeFeePending counts the payments Stripe has not settled yet (that can take a few minutes). Page through with before, using next from the previous page.

Refunds

A refund goes through Stripe on your workspace's own Stripe account. Leave out amountMinor to refund the rest of the payment, or give it in the smallest unit of the currency (500 is 5.00). reason is required: the payer sees it on their receipt, and it goes in the document's audit trail. The signed document stays signed.

A refund moves money, so it needs an Idempotency-Key. Send the same key again and you get the first answer back, with no second refund. The SDKs add a key for you and reuse it when they retry.

import { Docustay } from "@docustay2026/sdk";
const docustay = new Docustay(process.env.DOCUSTAY_API_KEY);
const paymentId = process.env.DOCUSTAY_PAYMENT_ID;   // from documents.payment.received or GET /api/v1/payments
const r = await docustay.refundPayment(paymentId, { amountMinor: 500, reason: "Charged twice" });
console.log(r.status, r.refundedLabel);   // "partially_refunded", "$5.00"
import os
from docustay import Docustay
docustay = Docustay(os.environ["DOCUSTAY_API_KEY"])
payment_id = os.environ["DOCUSTAY_PAYMENT_ID"]
docustay.refund_payment(payment_id, reason="Charged twice")   # the rest of the payment

From the command line, docustay payments refund <id> --reason "…" --yes does the same. It never runs without --yes, or a typed yes at the prompt.

From an AI assistant

The MCP server has search_documents and list_payments. It has no tool to refund a payment: that moves money, so a person does it in the app, from the command line or from their own code.

Plays and playbooks (your own sets of templates and skills) are covered in the template library.

CtrlI