SteveSteve

Submission Review

Operate Steve as a headless review queue through the external API.

The submission endpoints let an integrator run manual review outside the Steve UI.

Use them to:

  • list submissions for the authenticated company
  • fetch full detail, including file download URLs and event history
  • inspect and resolve fraud matches
  • approve, reject, or cancel submissions

Public status model

Steve exposes the following submission statuses through the external API:

StatusMeaning
createdSubmission record exists but processing has not started
processingSteve is running extraction and fraud checks
reviewHuman review is required
approvedApproved and waiting for or entering downstream sync
syncedApproved and synced downstream
rejectedRejected by a reviewer or integration
cancelledCancelled before approval or sync
failedProcessing failed for a non-review reason

For workflow sessions, GET /api/v1/jobs/{sessionId} tells you when processing is done. GET /api/v1/submissions/{submissionId} is the canonical read model for manual review.

List submissions

curl "$BASE_URL/api/v1/submissions?status=review&workflow=receipt-ocr&limit=20" \
  -H "Authorization: Bearer $STEVE_API_KEY"

Supported query parameters:

ParameterMeaning
workflowFilter to one workflow slug
statusFilter by public submission status
fraudStatusFilter by clean, flagged, or blocked
cursorContinue from a previous page
limitPage size, clamped to 1..100

Example response:

{
  "data": [
    {
      "id": "jx7sub456submissions",
      "submissionStatus": "review",
      "fraudStatus": "flagged",
      "fraudScore": 72.5,
      "workflow": {
        "slug": "receipt-ocr",
        "name": "Receipt OCR",
        "version": 3
      },
      "extractedData": {
        "merchantName": "Biedronka",
        "totalAmount": 123.45
      },
      "confidence": 0.96,
      "createdAt": "2026-03-25T10:00:00.000Z",
      "clientSubmissionId": "order-1711353600000"
    }
  ],
  "pagination": {
    "hasMore": false,
    "nextCursor": null
  }
}

Notes:

  • timestamps are ISO 8601 strings
  • clientSubmissionId is the caller-supplied idempotency key from session creation
  • extractedData may be partial or complete depending on processing state

Get submission detail

curl "$BASE_URL/api/v1/submissions/jx7sub456submissions" \
  -H "Authorization: Bearer $STEVE_API_KEY"

Example response:

{
  "id": "jx7sub456submissions",
  "submissionStatus": "review",
  "fraudStatus": "flagged",
  "fraudScore": 72.5,
  "extractedData": {
    "merchantName": "Biedronka",
    "totalAmount": 123.45,
    "currency": "PLN"
  },
  "confidence": 0.96,
  "fieldConfidences": {
    "merchantName": 0.99,
    "totalAmount": 0.95
  },
  "certainty": 0.94,
  "aiSummary": "Receipt from Biedronka with one flagged fraud match.",
  "failedReason": null,
  "rejectReason": null,
  "cancelReason": null,
  "workflow": {
    "id": "jx7wf001workflows",
    "slug": "receipt-ocr",
    "name": "Receipt OCR",
    "version": 3
  },
  "files": [
    {
      "id": "jx7file001submissionFiles",
      "fileIndex": 0,
      "label": "receipt",
      "mimeType": "image/jpeg",
      "fileSize": 245120,
      "downloadUrl": "https://r2.example.com/files/receipt.jpg?X-Amz-Signature=abc123"
    }
  ],
  "fraudMatches": [
    {
      "id": "jx7fm001submissionFraudMatches",
      "checkType": "visual",
      "score": 72.5,
      "similarity": 0.88,
      "status": "flag",
      "resolution": null,
      "resolvedBy": null,
      "resolvedAt": null
    }
  ],
  "events": [
    {
      "type": "ready_for_review",
      "occurredAt": "2026-03-25T10:01:40.000Z",
      "details": {
        "compliance": 0.96,
        "fraudStatus": "flagged"
      }
    }
  ],
  "clientSubmissionId": "order-1711353600000",
  "metadata": {
    "orderId": "12345"
  },
  "createdAt": "2026-03-25T10:00:00.000Z"
}

Important details:

  • file download URLs are pre-signed and valid for one hour
  • events are newest-first and capped at 100 entries
  • rejectReason and cancelReason are exposed on rejected or cancelled submissions

Fraud match workflow

If a submission is flagged or blocked, inspect the linked fraud matches:

curl "$BASE_URL/api/v1/submissions/jx7sub456submissions/fraud-matches" \
  -H "Authorization: Bearer $STEVE_API_KEY"

Response shape:

{
  "data": [
    {
      "id": "jx7fm001submissionFraudMatches",
      "checkType": "visual",
      "score": 72.5,
      "similarity": 0.88,
      "status": "flag",
      "resolution": null,
      "resolvedAt": null,
      "targetSubmission": {
        "id": "jx7sub200submissions",
        "createdAt": "2026-03-25T09:43:20.000Z"
      }
    }
  ],
  "pagination": {
    "hasMore": false,
    "nextCursor": null
  }
}

Resolve one match:

curl "$BASE_URL/api/v1/submissions/jx7sub456submissions/fraud-matches/jx7fm001submissionFraudMatches/resolve" \
  -X POST \
  -H "Authorization: Bearer $STEVE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"resolution":"false_positive"}'

Allowed resolutions:

  • false_positive
  • confirmed_fraud

Approvals are blocked while unresolved fraud matches remain.

Approve, reject, and cancel

Approve

Approves a submission that is currently in review.

curl "$BASE_URL/api/v1/submissions/jx7sub456submissions/approve" \
  -X POST \
  -H "Authorization: Bearer $STEVE_API_KEY"

Response:

{
  "submissionId": "jx7sub456submissions",
  "workflow": {
    "slug": "receipt-ocr",
    "version": 3
  },
  "submissionStatus": "approved"
}

Approval triggers Steve's downstream sync path. Later reads may show synced.

Reject

Reject requires a human-readable reason.

curl "$BASE_URL/api/v1/submissions/jx7sub456submissions/reject" \
  -X POST \
  -H "Authorization: Bearer $STEVE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reason":"Document is illegible and cannot be verified."}'

Cancel

Cancel is available until the submission reaches approved or synced. The reason is optional.

curl "$BASE_URL/api/v1/submissions/jx7sub456submissions/cancel" \
  -X POST \
  -H "Authorization: Bearer $STEVE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reason":"Duplicate submission from the same customer."}'

Operational guidance

  • Use GET /api/v1/jobs/{sessionId} to know when a submission is ready for review.
  • Use GET /api/v1/submissions/{submissionId} as the canonical source of truth after any action.
  • If you need file bytes, fetch them immediately after retrieving submission detail because download URLs expire.
  • POST review actions share the write rate-limit bucket. See Error Handling.
  • Webhooks are useful for notification, but the safest way to render a review UI is still to refetch the submission after each event.

On this page