Skip to main content
Evidence records store supporting files and records — receipts, statements, screenshots, scanned documents, contracts — that substantiate transactions. Evidence attaches to transactions (whereas documents attach to clients), and supports the same lifecycle: upload → submit → officer verify/reject, plus OCR field extraction.

Creating Evidence Records

Evidence is created in two steps: create the record, then upload the file. The high-level upload helper combines both.
// Low-level: create a record, get presigned URL, upload, confirm
const { evidence, upload } = await sdk.evidence.create({
  scope: "MX",
  type: "contrato_compraventa",
  contentType: "application/pdf",
  transactionIds: ["txn_abc123"],
});

await fetch(upload.url, {
  method: "PUT",
  body: fileBlob,
  headers: { "Content-Type": "application/pdf" },
});

await sdk.evidence.confirmUpload({
  id: evidence.id,
  filename: "contrato.pdf",
  contentType: "application/pdf",
  size: fileBlob.size,
});

console.log(evidence.id);
console.log(evidence.status); // "pending_upload"
// High-level helper: create + upload + confirm in one call
const evidence = await sdk.evidence.upload(file, {
  scope: "MX",
  type: "contrato_compraventa",
  transactionIds: ["txn_abc123"],
}, {
  onProgress: (progress) => console.log(`${Math.round(progress * 100)}%`),
  signal: abortController.signal,
});

Retry a Failed Upload

If the storage PUT step fails but the record was already created:
const evidence = await sdk.evidence.retryUpload("evid_xyz789", file);

Retrieving Evidence

const evidence = await sdk.evidence.retrieve("evid_xyz789");

console.log(evidence.id);
console.log(evidence.type);
console.log(evidence.status);
console.log(evidence.isAvailable);
You can also look up evidence by metadata:
const evidence = await sdk.evidence.retrieveByMetadata("internalRef", "REF-001");

Downloading Evidence

const { url, expiresAt } = await sdk.evidence.getDownloadUrl("evid_xyz789");

Updating Evidence

const updated = await sdk.evidence.update("evid_xyz789", {
  metadata: {
    reviewedBy: "admin@example.com",
  },
});

Review Lifecycle

Evidence follows the same review lifecycle as documents — submit an uploaded record for officer review, then verify or reject it.
await sdk.evidence.submit("evid_xyz789");          // uploaded → pending_review
await sdk.evidence.verify("evid_xyz789");           // pending_review → verified
await sdk.evidence.reject("evid_xyz789", {          // pending_review → rejected
  reason: "Illegible scan",
});

OCR Extraction

Extract structured fields from an evidence file via the OCR pipeline:
const result = await sdk.evidence.extract("evid_xyz789");
// Returns structured fields extracted from the evidence file

Linking Evidence to Transactions

Evidence can be linked to transactions from either side. Use the evidence resource:
await sdk.evidence.linkTransaction({
  evidenceId: "evid_xyz789",
  transactionId: "txn_abc123",
});

await sdk.evidence.unlinkTransaction({
  evidenceId: "evid_xyz789",
  transactionId: "txn_abc123",
});

// Replace all transaction links at once
await sdk.evidence.setTransactions({
  evidenceId: "evid_xyz789",
  transactionIds: ["txn_abc123", "txn_def456"],
});
Or link from the transaction side:
await sdk.transactions.linkEvidence({
  transactionId: "txn_abc123",
  evidenceId: "evid_xyz789",
});

await sdk.transactions.unlinkEvidence({
  transactionId: "txn_abc123",
  evidenceId: "evid_xyz789",
});

Listing Evidence

All Evidence

const { data } = await sdk.evidence.list({
  limit: 50,
});

For a Transaction

List all evidence linked to a transaction — from either resource:
const { data } = await sdk.evidence.listForTransaction("txn_abc123");

// Or from the transaction side
const { data: evidenceList } = await sdk.transactions.listEvidence("txn_abc123");

Linked Transaction IDs

const transactionIds = await sdk.evidence.listLinkedTransactions("evid_xyz789");

Async Iterator

for await (const evidence of sdk.evidence.iterate()) {
  console.log(evidence.id, evidence.type);
}

Checking Evidence Existence

// Check if a transaction has at least one verified evidence of a given type
const hasCfdi = await sdk.evidence.hasEvidenceType(
  "txn_abc123",
  "factura_cfdi_4_0",
);

if (!hasCfdi) {
  console.log("Transaction is missing a CFDI");
}

Counting Evidence

const count = await sdk.evidence.count({ type: "contrato_compraventa" });
console.log(`${count} matching evidence records`);

Deleting Evidence

await sdk.evidence.delete("evid_xyz789");

Batch Operations

Create or update multiple evidence records at once:
const result = await sdk.evidence.createMany([
  { scope: "MX", type: "contrato_compraventa", transactionIds: ["txn_abc123"] },
  { scope: "MX", type: "comprobante_pago", transactionIds: ["txn_abc123"] },
]);

const updated = await sdk.evidence.updateMany([
  { id: "evid_1", data: { metadata: { reviewed: true } } },
]);

Upsert

Create or update evidence by your own external ID:
const result = await sdk.evidence.upsertByExternalId({
  externalId: "erp-evid-123",
  scope: "MX",
  type: "contrato_compraventa",
  transactionIds: ["txn_abc123"],
});
console.log(result.action); // "created" | "updated"

const batch = await sdk.evidence.upsertManyByExternalId([...items]);