Receipts and bills waiting for someone to confirm the category, and the call that confirms one.
2 endpoints, each with the fields it takes and the fields it gives back.
GET/review-queue
Returns pending AI-categorized expenses awaiting human review.
- Leave
entityIdout to read the queue across every business in your account at once. A key limited to particular businesses is the exception: unless it is limited to exactly one, it has to name the one it wants. - This list is limited rather than paged:
hasMoresays whether more is waiting behind thelimityou asked for. limitcountshighConfidenceandneedsReviewtogether.highConfidenceholds the items the AI scored high enough to accept in a batch; everything else is inneedsReview. Each item carries theconfidencethe split used, which isnullwhen the AI never scored it.
Needs the review:read permission. A Read only key has it.
Query parameters
entityId
Typestring
RequiredOptional
Details
- a uuid
limit
Typeinteger
RequiredOptional
Details
- 1 to 100, default 50
| Field | Type | Required | Details |
|---|---|---|---|
| entityId | string | Optional |
|
| limit | integer | Optional |
|
Request
curl "https://www.numm.io/api/v1/review-queue?entityId=0190a1b2-c3d4-7e5f-8a9b-0c1d2e3f1002" \
-H "Authorization: Bearer nmo_live_REPLACE_WITH_YOUR_KEY"Response 200
{
"hasMore": false,
"highConfidence": [],
"needsReview": [
{
"id": "0190a1b2-c3d4-7e5f-9a9b-0c1d2e3f1008",
"date": "2026-02-05",
"amount": {
"cents": "500",
"formatted": "$5.00",
"currency": "USD"
},
"vendor": "Office Depot",
"description": null,
"proposedAccountId": "0190a1b2-c3d4-7e5f-8a9b-0c1d2e3f1003",
"proposedAccount": "Office Expense",
"confidence": null,
"rationale": null
}
]
}Response fields
highConfidence
Typearray of object
PresentAlways
highConfidence[].id
Typestring
PresentAlways
Details
- a uuid
highConfidence[].date
Typestring
PresentAlways
Details
- a date like 2026-09-20
highConfidence[].amount
Typemoney
PresentAlways
Details
- an object:
cents(whole cents as a digit string, in the currency beside it),formatted(a display string, not something to parse),currency(a three-letter code)
highConfidence[].vendor
Typestring or null
PresentAlways
highConfidence[].description
Typestring or null
PresentAlways
highConfidence[].proposedAccountId
Typestring or null
PresentAlways
Details
- a uuid
highConfidence[].proposedAccount
Typestring or null
PresentAlways
highConfidence[].confidence
Typenumber or null
PresentAlways
highConfidence[].rationale
Typestring or null
PresentAlways
needsReview
Typearray of object
PresentAlways
needsReview[].id
Typestring
PresentAlways
Details
- a uuid
needsReview[].date
Typestring
PresentAlways
Details
- a date like 2026-09-20
needsReview[].amount
Typemoney
PresentAlways
Details
- an object:
cents(whole cents as a digit string, in the currency beside it),formatted(a display string, not something to parse),currency(a three-letter code)
needsReview[].vendor
Typestring or null
PresentAlways
needsReview[].description
Typestring or null
PresentAlways
needsReview[].proposedAccountId
Typestring or null
PresentAlways
Details
- a uuid
needsReview[].proposedAccount
Typestring or null
PresentAlways
needsReview[].confidence
Typenumber or null
PresentAlways
needsReview[].rationale
Typestring or null
PresentAlways
hasMore
Typeboolean
PresentAlways
| Field | Type | Present | Details |
|---|---|---|---|
| highConfidence | array of object | Always | |
| highConfidence[].id | string | Always |
|
| highConfidence[].date | string | Always |
|
| highConfidence[].amount | money | Always |
|
| highConfidence[].vendor | string or null | Always | |
| highConfidence[].description | string or null | Always | |
| highConfidence[].proposedAccountId | string or null | Always |
|
| highConfidence[].proposedAccount | string or null | Always | |
| highConfidence[].confidence | number or null | Always | |
| highConfidence[].rationale | string or null | Always | |
| needsReview | array of object | Always | |
| needsReview[].id | string | Always |
|
| needsReview[].date | string | Always |
|
| needsReview[].amount | money | Always |
|
| needsReview[].vendor | string or null | Always | |
| needsReview[].description | string or null | Always | |
| needsReview[].proposedAccountId | string or null | Always |
|
| needsReview[].proposedAccount | string or null | Always | |
| needsReview[].confidence | number or null | Always | |
| needsReview[].rationale | string or null | Always | |
| hasMore | boolean | Always |
Errors
entity_not_allowed
Status403
MeaningYour key is limited to certain businesses, and this is not one of them.
not_found
Status404
MeaningThere is no such record, or none your key can reach.
| Status | Code | Meaning |
|---|---|---|
| 403 | entity_not_allowed | Your key is limited to certain businesses, and this is not one of them. |
| 404 | not_found | There is no such record, or none your key can reach. |
Every endpoint can also return:
invalid_key
Status401
MeaningYour key is missing, malformed, revoked, or expired.
insufficient_scope
Status403
MeaningYour key does not carry the scope this endpoint needs.
rate_limited
Status429
MeaningYou've made too many requests for this key. The retry-after header says how long to wait.
validation_failed
Status422
MeaningSomething in the path, the query, or the body did not pass validation.
internal_error
Status500
MeaningSomething went wrong on our side. Try again.
| Status | Code | Meaning |
|---|---|---|
| 401 | invalid_key | Your key is missing, malformed, revoked, or expired. |
| 403 | insufficient_scope | Your key does not carry the scope this endpoint needs. |
| 429 | rate_limited | You've made too many requests for this key. The retry-after header says how long to wait. |
| 422 | validation_failed | Something in the path, the query, or the body did not pass validation. |
| 500 | internal_error | Something went wrong on our side. Try again. |
POST/review-queue/{id}/accept
Posts a pending review-queue expense, under the proposed account or one you name.
- With no
accountId, the category the AI proposed is used. - If the item has no proposed category, you have to send one.
Needs the review:write permission. Only a Read and write key has it.
Path parameters
id
Typestring
RequiredRequired
Details
- a uuid
| Field | Type | Required | Details |
|---|---|---|---|
| id | string | Required |
|
Body fields
accountId
Typestring
RequiredOptional
Details
- a uuid
| Field | Type | Required | Details |
|---|---|---|---|
| accountId | string | Optional |
|
Request
curl -X POST "https://www.numm.io/api/v1/review-queue/0190a1b2-c3d4-7e5f-9a9b-0c1d2e3f1008/accept" \
-H "Authorization: Bearer nmo_live_REPLACE_WITH_YOUR_KEY" \
-H "Idempotency-Key: 0190a1b2-c3d4-7e5f-8a9b-0c1d2e3fee00"Response 200
{
"ok": true
}Response fields
ok
Typeboolean
PresentAlways
Details
- always true
| Field | Type | Present | Details |
|---|---|---|---|
| ok | boolean | Always |
|
This call takes an optional Idempotency-Key header. Repeat the same request with the same key within 24 hours and you get the first response back, with an idempotent-replayed: true header, and the work does not run twice. The same key with a different request is refused. See Idempotency and safe retries.
Errors
not_found
Status404
MeaningThere is no such record, or none your key can reach.
period_locked
Status409
MeaningThe date falls inside a closed period, so nothing can post to it.
read_only_billing_state
Status402
MeaningYour subscription is past due, so your books are read only for now.
conflict
Status409
MeaningThe request clashed with something that already happened.
| Status | Code | Meaning |
|---|---|---|
| 404 | not_found | There is no such record, or none your key can reach. |
| 409 | period_locked | The date falls inside a closed period, so nothing can post to it. |
| 402 | read_only_billing_state | Your subscription is past due, so your books are read only for now. |
| 409 | conflict | The request clashed with something that already happened. |
Every endpoint can also return:
invalid_key
Status401
MeaningYour key is missing, malformed, revoked, or expired.
insufficient_scope
Status403
MeaningYour key does not carry the scope this endpoint needs.
rate_limited
Status429
MeaningYou've made too many requests for this key. The retry-after header says how long to wait.
validation_failed
Status422
MeaningSomething in the path, the query, or the body did not pass validation.
internal_error
Status500
MeaningSomething went wrong on our side. Try again.
| Status | Code | Meaning |
|---|---|---|
| 401 | invalid_key | Your key is missing, malformed, revoked, or expired. |
| 403 | insufficient_scope | Your key does not carry the scope this endpoint needs. |
| 429 | rate_limited | You've made too many requests for this key. The retry-after header says how long to wait. |
| 422 | validation_failed | Something in the path, the query, or the body did not pass validation. |
| 500 | internal_error | Something went wrong on our side. Try again. |