# Continue question research

Source: https://docs.musicnerd.net/api-reference/research/continue

Continue after a saved-candidate answer attempt

## POST /api/artist/{id}/research/questions/{jobId}/continue

Full OpenAPI specification: https://docs.musicnerd.net/spec/question-research.json

## Authentication

This operation requires one of the security alternatives in the specification below. Security scheme definitions are included where present in the published specification.

[Authentication guide](https://docs.musicnerd.net/authentication)

## Operation and referenced schemas

```json
{
  "openapi": "3.1.0",
  "info": {
    "title": "Question-directed artist research",
    "version": "0.1.0",
    "description": "Preview contract. Apply the Web-owned research schema before enabling the matching API implementation. Web Ask About reserves a bounded planning slot before its model call: at most 10 new question plans per artist and 200 globally over rolling 24 hours, recorded without question or conversation text. This is separate from the API research ledgers; polling existing jobs does not plan again. Rejected reservations perform no model call. Planning uses no automatic model retries."
  },
  "servers": [
    {
      "url": "https://musicnerd-api.vercel.app"
    }
  ],
  "paths": {
    "/api/artist/{id}/research/questions/{jobId}/continue": {
      "post": {
        "summary": "Continue after a saved-candidate answer attempt",
        "description": "Service-only, idempotent transition of a candidate job into ordinary bounded research. Send no body or an empty JSON object; client routing, counters, permissions and source overrides are rejected. The same job ID, original neutral request, activity, quota lane, created time and model/provider counters are preserved. A candidate job transitions atomically once under the artist/job lock, subject to current claim, original lifetime and the one-active-question limit. Repeated calls return the current job status. Clients must fence an in-flight candidate answer lease before continuing, retain answer registration, and retry the checked answer against the new current references. This operation does not extend budgets, expiry or reset answer retry limits. It never decides that candidate evidence is sufficient. New-budget continuation preserves the single global saved admission and does not charge outside allowance; that is reserved only if validated external collection becomes necessary.",
        "security": [
          {
            "ResearchService": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "jobId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Persisted acknowledgement",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid authentication",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Current claimant/admin required for private operations",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unavailable artist, job or evidence",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "State or revision changed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "410": {
            "description": "Original candidate job lifetime expired; no counters or expiry were reset",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Evidence exceeds supported bounds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Research quota or active-work limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "For a quota response, matches retryAfterSeconds from its actual rolling-window boundary. Active-work conflicts retain a short retry hint.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            }
          },
          "503": {
            "description": "Storage, credential or provider unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Status": {
        "type": "object",
        "required": [
          "status",
          "jobId",
          "stage",
          "message",
          "updatedAt",
          "references",
          "limitations"
        ],
        "properties": {
          "status": {
            "const": "ok"
          },
          "jobId": {
            "type": "string",
            "format": "uuid"
          },
          "stage": {
            "type": "string",
            "enum": [
              "checking_saved",
              "searching",
              "reading",
              "transcribing",
              "waiting_provider",
              "complete",
              "unresolved",
              "failed",
              "cancelled"
            ]
          },
          "message": {
            "type": "string"
          },
          "provider": {
            "type": [
              "string",
              "null"
            ]
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "reused": {
            "type": "boolean"
          },
          "references": {
            "type": "array",
            "maxItems": 6,
            "items": {
              "$ref": "#/components/schemas/Reference"
            }
          },
          "limitations": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "outsideResearchReason": {
            "type": "string",
            "enum": [
              "quota"
            ],
            "description": "Outside collection was not admitted. Saved sources may still provide a bounded answer. New quota-blocked jobs include a shared quota scope and reset time; retry from a new question after reset, without restarting this terminal job. Older saved-only jobs can omit reset metadata."
          },
          "selection": {
            "type": "string",
            "enum": [
              "candidates",
              "research"
            ],
            "description": "Optional for legacy jobs. candidates is an unassessed evidence selection, not an answer or a sufficiency finding. If the checked answer is insufficient, continue this same job. research means the normal bounded research path."
          },
          "quotaScope": {
            "type": "string",
            "enum": [
              "saved_global",
              "outside_artist",
              "outside_global"
            ],
            "description": "Shared operational budget that blocked this work, never a personal visitor limit."
          },
          "retryAfterSeconds": {
            "type": "integer",
            "minimum": 0,
            "description": "Seconds until resetAt, rounded up. A current status read recomputes this duration; new traffic can consume later capacity."
          },
          "resetAt": {
            "type": "string",
            "format": "date-time",
            "description": "Actual rolling-window boundary calculated when the quota was checked."
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "status",
          "error",
          "code"
        ],
        "properties": {
          "status": {
            "const": "error"
          },
          "error": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "quotaScope": {
            "type": "string",
            "enum": [
              "saved_global",
              "outside_artist",
              "outside_global"
            ],
            "description": "Shared operational budget that blocked this work, never a personal visitor limit."
          },
          "retryAfterSeconds": {
            "type": "integer",
            "minimum": 0,
            "description": "Seconds until resetAt, rounded up. A current status read recomputes this duration; new traffic can consume later capacity."
          },
          "resetAt": {
            "type": "string",
            "format": "date-time",
            "description": "Actual rolling-window boundary calculated when the quota was checked."
          }
        }
      },
      "Reference": {
        "type": "object",
        "required": [
          "sourceId",
          "revision",
          "start",
          "end",
          "text",
          "url",
          "curation"
        ],
        "properties": {
          "sourceId": {
            "type": "string",
            "description": "Stable current source reference, including latest:<spotify|deezer|inprocess>:<64hex> provider snapshot originals. Removing/changing the connected account or successfully refreshing away a hidden/removed item makes its old reference unavailable; changed originals have a different revision."
          },
          "revision": {
            "type": "string"
          },
          "start": {
            "type": "integer",
            "minimum": 0
          },
          "end": {
            "type": "integer",
            "minimum": 0
          },
          "text": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "curation": {
            "type": "string",
            "enum": [
              "approved",
              "pending"
            ]
          },
          "evidenceKind": {
            "type": "string",
            "enum": [
              "original_text",
              "caption",
              "provider_transcript"
            ]
          },
          "speaker": {
            "type": "string",
            "enum": [
              "not_applicable",
              "unverified"
            ]
          },
          "publishedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "retrievedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "truncated": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "activityDate": {
            "type": "string",
            "description": "Optional provider activity date. Preserves YYYY, YYYY-MM or full date/time precision. Never substitutes for source publication time."
          },
          "activityDateKind": {
            "type": "string",
            "enum": [
              "release",
              "moment"
            ],
            "description": "Meaning of activityDate. Exact catalog release-date claims require original catalog text, not publishedAt."
          }
        }
      }
    },
    "securitySchemes": {
      "ResearchService": {
        "type": "apiKey",
        "in": "header",
        "name": "X-MusicNerd-Research-Key",
        "description": "Server-only MUSICNERD_RESEARCH_API_KEY. Public evidence research only; never grants review or interview-history access."
      }
    }
  }
}
```
