curl --request POST \
--url https://api.moonbounce.ai/v1/decisions/{decision_id}/uploads \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"kind": "items"
}
'{
"environment": "production",
"upload_id": "upl_01900000-0000-7000-8000-000000000001",
"kind": "items",
"url": "https://api.moonbounce.ai/v1/uploads/upl_01900000-0000-7000-8000-000000000001/q2V8eJ3x9Ld0RwQm7yTnA4bKpZs1HcUoXvGfIjEtMWa",
"method": "PUT",
"expires_at": "2026-11-09T12:15:00Z",
"max_bytes": 52428800,
"max_lines": 50000
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"reason": "<string>",
"param": "<string>",
"details": {
"issues": [
{
"param": "<string>",
"code": "<string>",
"message": "<string>"
}
]
}
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"reason": "<string>",
"param": "<string>",
"details": {
"issues": [
{
"param": "<string>",
"code": "<string>",
"message": "<string>"
}
]
}
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"reason": "<string>",
"param": "<string>",
"details": {
"issues": [
{
"param": "<string>",
"code": "<string>",
"message": "<string>"
}
]
}
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"reason": "<string>",
"param": "<string>",
"details": {
"issues": [
{
"param": "<string>",
"code": "<string>",
"message": "<string>"
}
]
}
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"reason": "<string>",
"param": "<string>",
"details": {
"issues": [
{
"param": "<string>",
"code": "<string>",
"message": "<string>"
}
]
}
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"reason": "<string>",
"param": "<string>",
"details": {
"issues": [
{
"param": "<string>",
"code": "<string>",
"message": "<string>"
}
]
}
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"reason": "<string>",
"param": "<string>",
"details": {
"issues": [
{
"param": "<string>",
"code": "<string>",
"message": "<string>"
}
]
}
}
}Upload a dataset or structure file
Answers a single-use url to send one file to, so its content never has to be typed into a call. Then send the file with a plain PUT, no key needed: curl -sS -X PUT --data-binary @<file> <url>, which prints what was stored. kind: "items": a dataset file, one example per line (JSONL; each line is exactly one import_examples example, its claims optional), up to 50 MB and 50,000 lines. create_run and import_examples then take its lines as items_from: {upload_id, offset?, limit?}, 200 a call. Refused (400 CONTENT_NOT_KEPT) on a decision that keeps no content (store_state: false). kind: "structure": a decision file ({decision_id?, structure, objective?}) or a bare structure, up to 1 MB; the PUT validates it as POST /v1/validate does and answers its structure_hash, which a dry run (evaluate or create_run) can name, and POST /v1/decisions can register by hash, while the upload lives. The URL takes the file for 15 minutes (expires_at), and a send then has 15 minutes to arrive; once received, calls can name the upload for about a day. A send that fails (other than by running out of time) gives the URL at least 15 more minutes for another try, up to an hour after the upload was created. Each call makes a new upload, so it takes no Idempotency-Key: one never sent expires unused. A team holds at most 200 unexpired items uploads and 1,000 structure uploads (409 UPLOADS_LIMIT past that). The URL carries its own authorization, so keep it out of anything shared.
curl --request POST \
--url https://api.moonbounce.ai/v1/decisions/{decision_id}/uploads \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"kind": "items"
}
'{
"environment": "production",
"upload_id": "upl_01900000-0000-7000-8000-000000000001",
"kind": "items",
"url": "https://api.moonbounce.ai/v1/uploads/upl_01900000-0000-7000-8000-000000000001/q2V8eJ3x9Ld0RwQm7yTnA4bKpZs1HcUoXvGfIjEtMWa",
"method": "PUT",
"expires_at": "2026-11-09T12:15:00Z",
"max_bytes": 52428800,
"max_lines": 50000
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"reason": "<string>",
"param": "<string>",
"details": {
"issues": [
{
"param": "<string>",
"code": "<string>",
"message": "<string>"
}
]
}
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"reason": "<string>",
"param": "<string>",
"details": {
"issues": [
{
"param": "<string>",
"code": "<string>",
"message": "<string>"
}
]
}
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"reason": "<string>",
"param": "<string>",
"details": {
"issues": [
{
"param": "<string>",
"code": "<string>",
"message": "<string>"
}
]
}
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"reason": "<string>",
"param": "<string>",
"details": {
"issues": [
{
"param": "<string>",
"code": "<string>",
"message": "<string>"
}
]
}
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"reason": "<string>",
"param": "<string>",
"details": {
"issues": [
{
"param": "<string>",
"code": "<string>",
"message": "<string>"
}
]
}
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"reason": "<string>",
"param": "<string>",
"details": {
"issues": [
{
"param": "<string>",
"code": "<string>",
"message": "<string>"
}
]
}
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"reason": "<string>",
"param": "<string>",
"details": {
"issues": [
{
"param": "<string>",
"code": "<string>",
"message": "<string>"
}
]
}
}
}Authorizations
An API key, sent as Authorization: Bearer <key>. Each operation lists the scope its key needs: decisions:evaluate (evaluate and read evaluations), decisions:feedback (your app's feedback) or decisions:develop (everything else, including owner feedback and the review queue). An operation listing no scope takes any scoped key. A key with no scope, or without the operation's, gets 403 INSUFFICIENT_SCOPE.
Scopes
Path Parameters
A name you choose for this decision, such as refund-exception: a lowercase letter, then up to 127 of a-z 0-9 _ . -. Unique in your organization and shared by its test and production keys. The first registration or evaluation under a new one creates the decision.
^[a-z][a-z0-9_.-]{0,127}$Body
items: a dataset file, one example per line (JSONL), named later by upload_id in items_from. structure: a decision file or a bare structure, named later by its structure_hash.
items, structure Response
The upload, waiting for its file
The environment of the key that made the call: production or test. Evaluations, feedback, reviews and suggestions are separate per environment; decisions and their versions belong to the whole organization.
production, test ^upl_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$items: a dataset file, one example per line (JSONL), named later by upload_id in items_from. structure: a decision file or a bare structure, named later by its structure_hash.
items, structure Send the file here, once, before expires_at: curl -sS -X PUT --data-binary @<file> <url>. It carries its own authorization (no key), so keep it out of anything shared.
PUT When the URL stops taking the file. Create another upload after that.
The most bytes the file may hold.
The most lines an items file may hold.