Release verification
Checklist from ingest through payment and reconcile. Run it against a disposable database after npm run db:seed, with Redis, npm run worker, and the application running.
The seed command creates a demo workspace and prints an API key. Do not seed a database that holds a production workspace.
| Role | |
|---|---|
| admin@custara.demo | admin |
| approver@custara.demo | approver |
| approver2@custara.demo | approver |
| payer@custara.demo | payer |
| auditor@custara.demo | auditor |
1. Bootstrap
GET /api/healthreturnsok: true- Seed organization is present
- Worker logs show the queues ready
2. Seed invoices
| external_id | Expected status |
|---|---|
| inv_small_001 | approved |
| inv_dual_002 | pending_approval |
| inv_bankchange_003 | needs_review |
| inv_newvendor_004 | needs_review |
| inv_dup_005 | duplicate_suspected |
| inv_arc_usdc_006 | needs_review (destination_not_allowlisted) |
3. Inbox upload
- Sign in as admin and open
/app/inbox. - Upload
fixtures/invoices/low-confidence.json. Status isneeds_reviewwith a confidence hold. - Upload a supplier PDF from your own files and confirm extract + policy run.
4. CSV bulk
- Upload
fixtures/csv/bulk-ap.csvfrom Inbox POST /api/v1/invoices/bulkwith a CSV body, bearer key, andIdempotency-Key
5. API sync and async
curl -s https://custara.xyz/api/v1/invoices -H "Authorization: Bearer $KEY" \
-H "Idempotency-Key: qa-sync-1" -H "Content-Type: application/json" \
-d @<(jq -n --slurpfile d fixtures/invoices/low-confidence.json '{external_id:"qa_low",sync:true,document:$d[0]}')Expect needs_review for low confidence. Repeat with "sync": false and poll GET /api/v1/invoices/{id} until the status leaves extracting and received. Async ingest requires the worker.
6. Mailbox
Set MAILBOX_INBOUND_SECRET. Post to /api/ingest/mailbox as described in OpenAPI. After the worker runs, the invoice source is mailbox.
7. SFTP
Copy a fixture PDF into storage/sftp-drops/{orgId}/incoming/. On /app/connectors, process the drop. The file moves to processed/.
8. Vendor portal
On the vendor record, create an invite. Open /vendor/{token} and upload happy-ngn.pdf with a unique invoice number.
9. FIRS and ERP
curl -s https://custara.xyz/api/v1/einvoice/firs -H "Authorization: Bearer $KEY" \
-H "Idempotency-Key: qa-firs-1" -H "Content-Type: application/json" \
-d @fixtures/api/firs.json
curl -s https://custara.xyz/api/v1/erp/ingest -H "Authorization: Bearer $KEY" \
-H "Idempotency-Key: qa-erp-1" -H "Content-Type: application/json" \
-d @fixtures/api/erp-odoo.jsonOn /app/connectors, paste an Odoo API key and Connect. Posted vendor bills land in Inbox with external id odoo:{id}. After Arc pay, the Odoo bill shows the payment. Disconnect removes the stored key.
10. Dual approval
- First approver approves
inv_dual_002on/app/approvals. - The same user cannot approve twice.
- Second approver completes the decision. The invoice is
approvedand a recommended pay date is set.
11. Arc pay
Requires Circle credentials, ARC_PAYMENTS_LIVE=true, ARC_ALLOW_SIMULATED=false, ARC_CHAIN for the deployment, and a funded Circle agent wallet. A test network also requires ARC_ALLOW_LIVE_ON_TESTNET=true.
- Set payment mode to live. Provision the Circle agent, fund it with USDC, and sync.
- Ingest a USDC invoice with an Arc destination, then confirm the destination is on the allowlist.
- Clear review until the invoice is
approved. - Initiate payment. MFA applies at or above the organization threshold.
- The worker runs
arc_transfer. The payment mode isliveandtxHashis the Circle transaction hash.
Automated coverage: E2E=1 npm run test:e2e. The Arc file skips when Circle credentials are absent.
12. Nigeria export
Use an approved NGN invoice with no Arc endpoint.
- Initiate payment.
- The intent rail is
nigeria_sandboxand the status is exported. - Download the CSV from
/api/internal/exports/{intentId}with a session.
13. Pay guards
- Pay while status is
needs_reviewreturns an error - A user with MFA enabled who pays in live mode without a code receives a step-up error
- A user with MFA off can initiate a live payment under the threshold without a code
- Live API pay without
X-Custara-Step-Up, whenAPI_PAY_STEPUP_SECRETis set, returns 400
14. Reconcile
- Mark reconciled on a
payment_sentinvoice POST /api/v1/reconcilewithinvoice_idandamountsetsreconciled
15. Manual checks
WhatsApp webhook delivery, live Xero and QuickBooks OAuth, and production Circle email delivery are verified by hand.
Commands
npm run db:up
npx prisma db push && npm run db:seed
npm run worker
npm run dev
E2E=1 npm run test:e2e
