API pentru rezultatele câmpurilor
Citește din propriile sisteme câmpurile și răspunsurile trimise pentru documentele tale.
Signit are trei endpointuri HTTP doar pentru citire, pentru câmpurile Text, Casetă de bifare și Semnătură ale documentelor pe care le trimiți. Folosește-le ca să copiezi răspunsurile într-un CRM, ERP sau tabel. Ele returnează doar răspunsurile pe care un semnatar le-a trimis deja; răspunsurile netrimise rămân private pentru semnatar. Ciornele nu sunt vizibile.
Un token de citire poate doar să citească. Nu poate crea, trimite, semna sau modifica nimic.
Prima cerere în cinci minute
Pornește autentificat în Signit, cu cel puțin un document pe care un semnatar l-a terminat.
- Deschide Conexiune agent → API pentru rezultatele câmpurilor (sau mergi la
https://app.sign-it.ro/settings/api). Dă un nume tokenului, alege cât durează și apasă Creează tokenul. - Copiază tokenul. Signit îl afișează o singură dată și păstrează doar o amprentă.
- Salvează-l în variabila de mediu
SIGNIT_READ_TOKEN, apoi listează documentele modificate recent:
curl -sS -H "Authorization: Bearer $SIGNIT_READ_TOKEN" \
"https://app.sign-it.ro/api/v1/envelopes?limit=10"const response = await fetch("https://app.sign-it.ro/api/v1/envelopes?limit=10", {
headers: { Authorization: `Bearer ${process.env.SIGNIT_READ_TOKEN}` },
});
if (!response.ok) throw new Error(`Signit returned ${response.status}`);
const page = await response.json();
console.log(page.data);$headers = @{ Authorization = "Bearer $env:SIGNIT_READ_TOKEN" }
Invoke-RestMethod -Uri "https://app.sign-it.ro/api/v1/envelopes?limit=10" -Headers $headers- Ia un
iddindatași citește valorile trimise. Fiecare pagină de document din Signit afișează aceste cereri, gata de copiat, la Rezultatele câmpurilor.
curl -sS -H "Authorization: Bearer $SIGNIT_READ_TOKEN" \
"https://app.sign-it.ro/api/v1/envelopes/ENVELOPE_ID/field-results"const response = await fetch("https://app.sign-it.ro/api/v1/envelopes/ENVELOPE_ID/field-results", {
headers: { Authorization: `Bearer ${process.env.SIGNIT_READ_TOKEN}` },
});
if (!response.ok) throw new Error(`Signit returned ${response.status}`);
const results = await response.json();
console.log(results.values);$headers = @{ Authorization = "Bearer $env:SIGNIT_READ_TOKEN" }
Invoke-RestMethod -Uri "https://app.sign-it.ro/api/v1/envelopes/ENVELOPE_ID/field-results" -Headers $headersȚinta de cinci minute include crearea tokenului și aceste cereri. Crearea contului și semnarea unui exemplu nu fac parte din ea.
Tokenuri de citire
- Doar pentru citire, pentru documentele organizației selectate în momentul cererii. Dacă schimbi organizația, același token citește din cealaltă.
- Valabile implicit 30 de zile, cel mult 90. Poți avea 10 tokenuri active.
- Revocă un token oricând din API pentru rezultatele câmpurilor; următoarea cerere eșuează.
- Fiecare cerere este verificată cu contul tău așa cum este acum. Dacă contul este șters sau nu mai poate trimite, tokenurile lui nu mai funcționează.
- Tokenurile de citire și conexiunile de agent sunt separate: conectorul de agent nu acceptă un token de citire, iar aceste endpointuri nu acceptă un secret de agent.
- Păstrează tokenul într-un depozit de secrete. Răspunsurile de citire, URL-urile și jurnalele nu îl conțin.
Trimite-l ca Authorization: Bearer <token>. Fiecare răspuns are
Cache-Control: private, no-store.
Endpointuri
GET /api/v1/envelopes
Descoperire: documentele tale trimise, în ordinea (updatedAt, id).
| Parametru | Semnificație |
|---|---|
updatedAfter | Opțional, moment RFC 3339, inclusiv, de exemplu 2026-10-16T09:30:00.000000Z. |
limit | 1–100, implicit 50. |
cursor | nextCursor din pagina anterioară. Repetă aceiași alți parametri sau niciunul. |
Răspunsul conține data (fiecare element: id, status, subject,
externalReference, signingFormatVersion, definitionRevision,
updateRevision, updatedAt, sentAt, completedAt), hasMore,
nextCursor și scanThrough. Momentele sunt milisecunde întregi de la ceasul
aplicației Signit, scrise cu șase zecimale; ultimele trei sunt mereu 000.
updatedAfter păstrează doar milisecunde întregi: partea sub-milisecundă se
elimină, deci filtrul poate întoarce puțin mai mult decât ai cerut. Deduplică
după updateRevision, cum arată pașii de mai jos.
GET /api/v1/envelopes/{id}/fields
Definiția câmpurilor înghețată la trimitere: pentru fiecare câmp id, key,
type, label, required, signerId-ul semnatarului, poziția, iar pentru
câmpurile Text multiline și prefill. Un prefill cu locked: true este
textul expeditorului: face parte din definiție și nu este niciodată un
răspuns al semnatarului. Perechile tale metadata apar aici și nu ajung
niciodată la semnatari. signers listează semnatarii, iar
envelope.definitionRevision identifică această definiție.
GET /api/v1/envelopes/{id}/field-results
Doar valorile trimise:
values: câte o intrare pentru fiecare câmp al fiecărui semnatar care a terminat, cufieldId,key,type,value,provenance,actorKind,signerIdșisubmittedAt. Câmpurile Semnătură conțin numele adoptat.signers: fiecare semnatar custatus,completedAt,actorKindșiauditEventId-ul finalizării sale.state.signing:in_progress,completed(toți semnatarii au terminat),declined,expired,voidedsaufailed.state.terminalestetruecând nu mai pot sosi răspunsuri.state.artifacts:not_applicablepână se termină semnarea, apoipending,faileddacă generarea necesită o reîncercare, apoireadycu amprentele PDF-ului final și ale certificatului. Semnare terminată și documente gata sunt momente diferite.
Răspunsurile unui semnatar care nu a terminat nu apar niciodată, deci rezultatele pot fi parțiale cât timp semnarea este în curs.
Pentru documentele care au numai semnături, identitățile câmpurilor provin din
dovezile finalizării și folosesc cheile înghețate. Valorile includ
source: "legacy_signature_evidence" și evidence: { signerId, auditEventId }.
Dacă identitățile unei finalizări mai vechi nu pot fi recuperate, răspunsul
folosește projectionStatus: "legacy_evidence_only" cu signerSignatures,
fără să inventeze ID-uri. Dovezile trimise rămân disponibile.
provenance | Semnificație |
|---|---|
signer_entered | Semnatarul l-a scris sau ales. false aici este un „nu” explicit. |
sender_prefill_confirmed | Textul sugerat de expeditor, lăsat neschimbat și confirmat. |
not_provided | Text opțional omis: value este null. "" înseamnă lăsat gol explicit. |
unchecked_default | Casetă opțională neatinsă: value este false. |
adopted_signature | Numele adoptat de semnatar pentru un câmp Semnătură. |
actorKind este human_ui când semnatarul a folosit Signit sau
agent_credential când agentul său conectat a semnat pentru el.
Fiecare răspuns este citit dintr-un singur instantaneu consecvent al bazei de
date. Două cereri pot diferi dacă ceva s-a schimbat între ele: compară
definitionRevision când combini fields cu field-results.
Referință externă
Pe pagina unui document, în cardul Referință externă, poți salva propriul ID
pentru el (cel mult 200 de caractere). Revine ca externalReference, iar
schimbarea lui contează ca actualizare.
Interogare periodică pentru modificări
Descoperirea este interogare periodică limitată, nu un flux garantat de evenimente: o modificare poate apărea cu întârziere, iar un document care lipsește dintr-o pagină nu este șters.
- Prima rulare scanează fără
updatedAfter. - Urmează
nextCursorpână cândhasMoreestefalse. SalveazăscanThrough-ul scanării ca punct de control doar după ce ai procesat fiecare pagină. - Următoarea rulare cere
updatedAfter= punctul de control minus cinci minute. - Sari peste un document al cărui
updateRevisionl-ai procesat deja. Crește la fiecare modificare vizibilă: un răspuns trimis, un status final, documente gata, o referință externă nouă. - O dată pe zi, scanează din nou fără
updatedAfterpentru reconciliere.
Un cursor este valabil 15 minute, pentru același titular de token și aceiași
parametri. După invalid_cursor sau cursor_expired, pornește din nou
rularea de la punctul de control.
Rulează jobul următor o dată pe minut, fără execuții simultane. Furnizează funcțiile persistente handle și saveState descrise în exemplu. Repornește cursoarele expirate de cel mult trei ori și face o scanare completă cel puțin zilnic. O pagină ulterioară eșuată păstrează ultimul checkpoint complet. Oprește la 401, corectează parametrii 400 și reîncearcă la următoarea execuție după o întrerupere.
Un exemplu complet:
// signit-poll-example
const OVERLAP_MS = 5 * 60 * 1000;
const RECONCILE_MS = 24 * 60 * 60 * 1000;
async function getJson(url, token, attempt = 0) {
const response = await fetch(url, { headers: { Authorization: `Bearer ${token}` } });
if ((response.status === 429 || response.status === 503) && attempt < 5) {
const retryAfter = Number(response.headers.get("retry-after"));
const delayMs =
Number.isFinite(retryAfter) && retryAfter > 0
? Math.min(60_000, Math.max(1_000, retryAfter * 1000))
: Math.min(60_000, 1000 * 2 ** attempt);
await new Promise((resolve) => setTimeout(resolve, delayMs));
return getJson(url, token, attempt + 1);
}
const body = await response.json();
if (!response.ok) {
throw Object.assign(new Error(body.error?.message ?? `Signit returned ${response.status}`), {
code: body.error?.code,
status: response.status,
});
}
return body;
}
// Run once per minute with the latest durably loaded state, without concurrent runs.
// state = { checkpoint: null, lastReconciledAt: null, seen: {} }.
// handle must durably apply each idempotencyKey at most once. A crash between
// handle and saveState can repeat it. saveState must atomically persist its argument.
async function pollSignit({
baseUrl,
token,
state,
handle,
saveState,
now = Date.now,
limit = 100,
}) {
const fullScan =
!state.checkpoint ||
!state.lastReconciledAt ||
now() - Date.parse(state.lastReconciledAt) >= RECONCILE_MS;
const filters = new URLSearchParams({ limit: String(limit) });
if (!fullScan) {
filters.set("updatedAfter", new Date(Date.parse(state.checkpoint) - OVERLAP_MS).toISOString());
}
const persist = async (next) => {
await saveState(structuredClone(next));
Object.assign(state, next);
};
for (let restart = 0; ; restart++) {
let cursor = null;
let scanThrough = null;
try {
do {
const query = new URLSearchParams(filters);
if (cursor) query.set("cursor", cursor);
const page = await getJson(`${baseUrl}/api/v1/envelopes?${query}`, token);
scanThrough = page.scanThrough;
for (const envelope of page.data) {
if ((state.seen[envelope.id] ?? -1) >= envelope.updateRevision) continue;
let results;
try {
results = await getJson(
`${baseUrl}/api/v1/envelopes/${envelope.id}/field-results`,
token,
);
} catch (error) {
// Unavailable to this credential is not proof of deletion.
if (error.status === 404) continue;
throw error;
}
const revision = results.envelope.updateRevision;
await handle(results, { idempotencyKey: `${envelope.id}@${revision}` });
// Business data first, then durable dedupe, with the old checkpoint.
await persist({ ...state, seen: { ...state.seen, [envelope.id]: revision } });
}
cursor = page.nextCursor;
} while (cursor);
// Only a fully processed scan advances either completed checkpoint.
await persist({
...state,
checkpoint: scanThrough,
lastReconciledAt: fullScan ? new Date(now()).toISOString() : state.lastReconciledAt,
});
return state;
} catch (error) {
if (["invalid_cursor", "cursor_expired"].includes(error.code) && restart < 3) continue;
// Keep the last completed checkpoint on outage, bad parameters or lost authority.
// Correct invalid_parameter input or renew credentials before the next scheduled run.
throw error;
}
}
}Erori
Erorile arată astfel: { "error": { "code": "...", "message": "...", "requestId": "..." } }.
| Status | code | Ce faci |
|---|---|---|
| 400 | invalid_parameter | Corectează updatedAfter sau limit ori elimină parametrii necunoscuți. |
| 400 | invalid_cursor, cursor_expired | Pornește rularea din nou de la punctul de control. |
| 401 | unauthenticated, invalid_token | Trimite un token de citire valid, neexpirat și nerevocat. |
| 404 | not_found | Documentul nu există, nu este al tău sau este încă ciornă. |
| 429 | — | Așteaptă Retry-After sau reîncearcă de la 1 s, dublând până la 60 s. |
| 503 | unavailable | Aceeași reîncercare limitată; oprește-te după câteva încercări. |
| 500 | internal_error | Reîncearcă mai târziu; menționează requestId dacă persistă. |
Conectează ChatGPT
Adaugă conexiunea OAuth MCP Signit și creează Documente din atașamentele chatului.
Cum semnezi un PDF online gratuit, pas cu pas
Semnare document PDF cu semnătură electronică, online și gratuit. Încarci PDF-ul, adaugi Semnatarii și trimiți. Ei semnează fără cont, chiar de pe telefon.