{"openapi":"3.1.0","info":{"title":"ROCAR.AZ agent API","version":"1.0.0","summary":"Prepare and publish a car listing on ROCAR.AZ on behalf of its owner","description":"A vendor-neutral capability layer. Any client that can send a bearer token can use it:\nROCAR does not register with, and is not certified by, any AI provider.\n\nThe shape of the flow is fixed by one rule — an agent may prepare a listing, but only\nits owner may publish it. `submit` answers `USER_CONFIRMATION_REQUIRED` with a ROCAR\nURL until the owner has opened it and approved what is about to be published.\n\nDrafts are partial by design: send what you know, read `missingFields`, ask your user\nonly those questions, and send the answers back.","contact":{"url":"https://rocar.az/ai-agents"}},"servers":[{"url":"https://rocar.az/agent/v1"}],"security":[{"agentToken":[]}],"tags":[{"name":"discovery","description":"What this deployment supports"},{"name":"taxonomy","description":"ROCAR identifiers — never invent one"},{"name":"drafts","description":"Assemble a listing"},{"name":"media","description":"Photos and video, uploaded directly to storage"},{"name":"publication","description":"Owner confirmation and moderation"}],"paths":{"/capabilities":{"get":{"tags":["discovery"],"operationId":"getCapabilities","summary":"What this deployment lets an agent do","description":"Unauthenticated. Safe to call before a token exists.","security":[],"responses":{"200":{"description":"Capability document","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Capabilities"}}}}}}},"/me":{"get":{"tags":["discovery"],"operationId":"getMe","summary":"Which ROCAR account this token acts for","description":"Requires the `profile:read` scope.","responses":{"200":{"description":"Account and granted scopes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"description":"Missing, revoked or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentError"},"example":{"error":{"code":"AUTH_REQUIRED","message":"Missing, revoked or expired token"}}}}},"403":{"description":"The token lacks profile:read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentError"},"example":{"error":{"code":"INSUFFICIENT_SCOPE","message":"The token lacks profile:read"}}}}}}}},"/taxonomy/enums":{"get":{"tags":["taxonomy"],"operationId":"getTaxonomyEnums","summary":"Every closed vocabulary a draft field accepts","description":"Requires the `vehicle_taxonomy:read` scope.","responses":{"200":{"description":"Enum members, by field","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaxonomyEnums"}}}},"401":{"description":"Missing, revoked or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentError"},"example":{"error":{"code":"AUTH_REQUIRED","message":"Missing, revoked or expired token"}}}}}}}},"/taxonomy/makes":{"get":{"tags":["taxonomy"],"operationId":"listMakes","summary":"Vehicle makes","description":"Requires the `vehicle_taxonomy:read` scope.","parameters":[{"name":"vehicleType","in":"query","required":false,"schema":{"type":"string"},"description":"Narrow to one vehicle type from /taxonomy/enums."}],"responses":{"200":{"description":"Makes","content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Make"}}}}}}}}}},"/taxonomy/makes/{makeId}/models":{"get":{"tags":["taxonomy"],"operationId":"listModels","summary":"Models of one make","description":"Requires the `vehicle_taxonomy:read` scope.","parameters":[{"name":"makeId","in":"path","required":true,"schema":{"type":"string"}},{"name":"vehicleType","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Models","content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Model"}}}}}}}}}},"/taxonomy/models/{modelId}/years":{"get":{"tags":["taxonomy"],"operationId":"modelYears","summary":"Production range and selectable years for one model","description":"Requires the `vehicle_taxonomy:read` scope. Read this before choosing a year: `years` is the complete set the catalog accepts, newest first. `authority` says how sure that is — GENERATIONS (from the model's generations, the strongest answer), MODEL (the model's own confirmed span), or NONE (no source has been tied to this model, so any plausible year is accepted and you should ask the owner rather than guess).","parameters":[{"name":"modelId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Model years","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelYearRange"}}}}}}},"/taxonomy/makes/{makeId}/models/{modelId}/generations":{"get":{"tags":["taxonomy"],"operationId":"listGenerations","summary":"Generations of one model, compatible with a year when given","description":"Requires the `vehicle_taxonomy:read` scope. Pass `year` to receive only the generations that were in production that year — the same compatibility the website applies, so a pair accepted here is accepted on submit.","parameters":[{"name":"makeId","in":"path","required":true,"schema":{"type":"string"}},{"name":"modelId","in":"path","required":true,"schema":{"type":"string"}},{"name":"year","in":"query","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Generations","content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"modelId":{"type":"string"},"year":{"type":["integer","null"]},"generationCount":{"type":"integer"},"items":{"type":"array","items":{"$ref":"#/components/schemas/Generation"}}}}}}}}}},"/taxonomy/regions":{"get":{"tags":["taxonomy"],"operationId":"listRegions","summary":"Cities and districts a listing can be in","description":"Requires the `vehicle_taxonomy:read` scope.","responses":{"200":{"description":"Regions","content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Region"}}}}}}}}}},"/taxonomy/resolve":{"post":{"tags":["taxonomy"],"operationId":"resolveTaxonomy","summary":"Turn what a person said into ROCAR identifiers","description":"Requires the `vehicle_taxonomy:read` scope.\n\nReturns candidates rather than a guess when the text is ambiguous. Ask your user\nto choose instead of picking for them.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveTaxonomyRequest"},"example":{"make":"Mercedes","model":"E-class","region":"Bakı"}}}},"responses":{"200":{"description":"Matches and candidates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveTaxonomy"}}}}}}},"/listings/drafts":{"post":{"tags":["drafts"],"operationId":"createListingDraft","summary":"Start a listing from whatever is known so far","description":"Requires the `listing:draft:create` scope.\n\nSend any subset of fields. A partial draft is normal and is NOT an error: the\nresponse carries `missingFields` with a question per field, in Azerbaijani,\nRussian and English.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Repeat-safe key. The same key with the same body returns the first answer instead of acting twice; the same key with a different body is refused as IDEMPOTENCY_CONFLICT.","schema":{"type":"string","maxLength":128}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DraftValues"},"example":{"values":{"makeId":"cmr…","modelId":"cmr…","year":2022,"lastAskingPriceQapik":7800000}}}}},"responses":{"201":{"description":"Current state of the draft, including what ROCAR still needs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentDraft"}}}},"401":{"description":"Missing, revoked or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentError"},"example":{"error":{"code":"AUTH_REQUIRED","message":"Missing, revoked or expired token"}}}}},"403":{"description":"The token lacks listing:draft:create","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentError"},"example":{"error":{"code":"INSUFFICIENT_SCOPE","message":"The token lacks listing:draft:create"}}}}},"409":{"description":"Key reused with a different body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentError"},"example":{"error":{"code":"IDEMPOTENCY_CONFLICT","message":"Key reused with a different body"}}}}},"422":{"description":"A value is not in the ROCAR catalogue","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentError"},"example":{"error":{"code":"INVALID_TAXONOMY_VALUE","message":"A value is not in the ROCAR catalogue"}}}}},"429":{"description":"Too many requests for this integration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentError"},"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests for this integration"}}}}}}}},"/listings/drafts/{draftId}":{"get":{"tags":["drafts"],"operationId":"getListingDraft","summary":"Draft state, including what ROCAR still needs","description":"Requires the `listing:draft:read` scope.","parameters":[{"name":"draftId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Current state of the draft, including what ROCAR still needs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentDraft"}}}},"404":{"description":"No such draft for this integration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentError"},"example":{"error":{"code":"NOT_FOUND","message":"No such draft for this integration"}}}}}}},"patch":{"tags":["drafts"],"operationId":"updateListingDraft","summary":"Add what the owner has just told the agent","description":"Requires the `listing:draft:update` scope.\n\nOnly the keys you send are touched. When the last required field arrives, ROCAR\ncreates the real draft listing and the response carries `listingId`.","parameters":[{"name":"draftId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DraftValuesRequired"},"example":{"values":{"mileageKm":42000,"fuelType":"PETROL","regionId":"cmr…"}}}}},"responses":{"200":{"description":"Current state of the draft, including what ROCAR still needs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentDraft"}}}},"404":{"description":"No such draft for this integration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentError"},"example":{"error":{"code":"NOT_FOUND","message":"No such draft for this integration"}}}}},"409":{"description":"Already submitted; an agent can no longer edit it","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentError"},"example":{"error":{"code":"MODERATION_REQUIRED","message":"Already submitted; an agent can no longer edit it"}}}}},"422":{"description":"A value is not in the ROCAR catalogue","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentError"},"example":{"error":{"code":"INVALID_TAXONOMY_VALUE","message":"A value is not in the ROCAR catalogue"}}}}}}}},"/listings/drafts/{draftId}/validate":{"post":{"tags":["drafts"],"operationId":"validateListingDraft","summary":"What is still missing, and what would block publication","description":"Requires the `listing:validate` scope.","parameters":[{"name":"draftId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Draft state plus publication blockers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentDraftValidation"}}}},"404":{"description":"No such draft for this integration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentError"},"example":{"error":{"code":"NOT_FOUND","message":"No such draft for this integration"}}}}}}}},"/listings/drafts/{draftId}/media/upload-url":{"post":{"tags":["media"],"operationId":"createMediaUploadUrl","summary":"Signed target to upload one photo or video straight to storage","description":"Requires the `listing:media:upload` scope.\n\nBytes never pass through this API. Upload them to the returned target yourself,\nthen call the complete endpoint. ROCAR will not fetch a URL on your behalf.","parameters":[{"name":"draftId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Repeat-safe key. The same key with the same body returns the first answer instead of acting twice; the same key with a different body is refused as IDEMPOTENCY_CONFLICT.","schema":{"type":"string","maxLength":128}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaUploadRequest"}}}},"responses":{"201":{"description":"Signed upload session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaUploadSession"}}}},"422":{"description":"The draft is not complete enough to hold media","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentError"},"example":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"The draft is not complete enough to hold media"}}}}}}}},"/listings/drafts/{draftId}/media/uploads/{sessionId}/complete":{"post":{"tags":["media"],"operationId":"completeMediaUpload","summary":"Tell ROCAR the bytes have landed; processing starts","description":"Requires the `listing:media:upload` scope.","parameters":[{"name":"draftId","in":"path","required":true,"schema":{"type":"string"}},{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Registered media asset"},"409":{"description":"The upload failed validation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentError"},"example":{"error":{"code":"MEDIA_REJECTED","message":"The upload failed validation"}}}}}}}},"/listings/drafts/{draftId}/media":{"get":{"tags":["media"],"operationId":"getMediaStatus","summary":"Processing state of everything uploaded so far","description":"Requires the `listing:draft:read` scope.","parameters":[{"name":"draftId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Media pipeline state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaStatus"}}}}}}},"/listings/drafts/{draftId}/submit":{"post":{"tags":["publication"],"operationId":"submitListing","summary":"Send to ROCAR moderation — only with a confirmation the owner approved","description":"Requires the `listing:submit` scope.\n\nCall once with no body to receive `USER_CONFIRMATION_REQUIRED` and a\n`confirmationUrl`. Show that URL to your user. After they approve it in their own\nbrowser, call again with `confirmationId` and the listing enters ROCAR's standard\nmoderation queue — the same queue a listing created on the website enters.","parameters":[{"name":"draftId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Repeat-safe key. The same key with the same body returns the first answer instead of acting twice; the same key with a different body is refused as IDEMPOTENCY_CONFLICT.","schema":{"type":"string","maxLength":128}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitRequest"}}}},"responses":{"200":{"description":"Accepted for moderation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitResult"}}}},"409":{"description":"The owner has not confirmed yet. `details.confirmationUrl` is what you show them.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentError"},"example":{"error":{"code":"USER_CONFIRMATION_REQUIRED","message":"The owner has to confirm this listing before ROCAR will accept it","details":{"confirmationId":"cmu…","confirmationUrl":"https://rocar.az/account/agents/confirm/…"}}}}}},"422":{"description":"The draft is still incomplete","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentError"},"example":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"The draft is still incomplete"}}}}}}}},"/listings/{listingId}/status":{"get":{"tags":["publication"],"operationId":"getListingStatus","summary":"Where the listing is: draft, moderation, active, rejected","description":"Requires the `listing:draft:read` scope.","parameters":[{"name":"listingId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Listing lifecycle state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingStatus"}}}},"404":{"description":"Not a listing this integration created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentError"},"example":{"error":{"code":"NOT_FOUND","message":"Not a listing this integration created"}}}}}}}}},"components":{"securitySchemes":{"agentToken":{"type":"http","scheme":"bearer","description":"A ROCAR agent token. The account owner creates one at https://rocar.az/account/agents, picks the scopes, and pastes it into their agent. Tokens start with `rocar_ag_` and can be revoked there at any time."}},"schemas":{"AgentError":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["AUTH_REQUIRED","INSUFFICIENT_SCOPE","VALIDATION_ERROR","MISSING_REQUIRED_FIELDS","INVALID_TAXONOMY_VALUE","MEDIA_NOT_READY","MEDIA_REJECTED","DUPLICATE_LISTING","USER_CONFIRMATION_REQUIRED","RATE_LIMITED","MODERATION_REQUIRED","NOT_FOUND","IDEMPOTENCY_CONFLICT","FORBIDDEN"]},"message":{"type":"string"},"details":{"type":"object","additionalProperties":true}}}}},"Capabilities":{"type":"object","properties":{"version":{"type":"string"},"baseUrl":{"type":"string","format":"uri"},"openApiUrl":{"type":"string","format":"uri"},"mcpUrl":{"type":"string","format":"uri"},"documentationUrl":{"type":"string","format":"uri"},"connectUrl":{"type":"string","format":"uri"},"enabled":{"type":"boolean"},"scopes":{"type":"array","items":{"type":"string","enum":["profile:read","vehicle_taxonomy:read","listing:draft:create","listing:draft:read","listing:draft:update","listing:media:upload","listing:validate","listing:submit"]}},"limits":{"type":"object","properties":{"requestsPerMinute":{"type":"integer"},"draftsPerDay":{"type":"integer"},"mediaPerDraft":{"type":"integer"}}},"authorization":{"type":"object","properties":{"type":{"type":"string","const":"bearer"},"tokenPrefix":{"type":"string"},"grantUrl":{"type":"string","format":"uri"}}}}},"Me":{"type":"object","properties":{"integration":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"provider":{"type":["string","null"]}}},"scopes":{"type":"array","items":{"type":"string","enum":["profile:read","vehicle_taxonomy:read","listing:draft:create","listing:draft:read","listing:draft:update","listing:media:upload","listing:validate","listing:submit"]}},"user":{"type":"object","properties":{"id":{"type":"string"},"displayName":{"type":["string","null"]},"language":{"type":"string"},"role":{"type":"string"}}}}},"TaxonomyEnums":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}},"description":"Each key is a draft field; each value is the complete set it accepts."},"Make":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"modelCount":{"type":"integer"}}},"Model":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"bodyType":{"type":["string","null"]},"generationCount":{"type":"integer"}}},"ModelYearRange":{"type":"object","required":["modelId","authority","years"],"properties":{"modelId":{"type":"string"},"authority":{"type":"string","enum":["GENERATIONS","MODEL","NONE"]},"yearFrom":{"type":["integer","null"]},"yearTo":{"type":["integer","null"]},"inProduction":{"type":"boolean"},"years":{"type":"array","items":{"type":"integer"}},"generationCount":{"type":"integer"},"sourceUrl":{"type":["string","null"]}}},"Generation":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"code":{"type":["string","null"]},"yearFrom":{"type":"integer"},"yearTo":{"type":["integer","null"]},"isRestyling":{"type":"boolean"},"sourceUrl":{"type":["string","null"]}}},"Region":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"nameAz":{"type":"string"},"nameRu":{"type":"string"},"children":{"type":"array","items":{"type":"object"}}}},"ResolveTaxonomyRequest":{"type":"object","properties":{"make":{"type":"string","maxLength":80},"model":{"type":"string","maxLength":80},"region":{"type":"string","maxLength":80}}},"ResolveTaxonomy":{"type":"object","description":"`matched` is set only when exactly one row fits. Otherwise read `candidates` and ask.","additionalProperties":{"type":"object","properties":{"query":{"type":"string"},"matched":{"type":["object","null"]},"candidates":{"type":"array","items":{"type":"object"}}}}},"DraftValues":{"type":"object","properties":{"values":{"type":"object","additionalProperties":true,"description":"Any subset of listing fields. Ids come from the taxonomy endpoints; money is in qəpik (1 AZN = 100)."}}},"DraftValuesRequired":{"type":"object","required":["values"],"properties":{"values":{"type":"object","additionalProperties":true}}},"MissingField":{"type":"object","properties":{"field":{"type":"string"},"question":{"type":"object","properties":{"az":{"type":"string"},"ru":{"type":"string"},"en":{"type":"string"}}}}},"AgentDraft":{"type":"object","required":["draftId","status","missingFields"],"properties":{"draftId":{"type":"string"},"status":{"type":"string","enum":["draft_incomplete","draft_ready","submitted"]},"listingId":{"type":["string","null"]},"listingNumber":{"type":["integer","null"]},"listingStatus":{"type":["string","null"]},"missingFields":{"type":"array","items":{"$ref":"#/components/schemas/MissingField"}},"providedFields":{"type":"array","items":{"type":"string"}},"values":{"type":"object","additionalProperties":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"AgentDraftValidation":{"allOf":[{"$ref":"#/components/schemas/AgentDraft"},{"type":"object","properties":{"publishable":{"type":"boolean"},"blockers":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}]},"MediaUploadRequest":{"type":"object","required":["contentType","sizeBytes"],"properties":{"contentType":{"type":"string","example":"image/jpeg"},"sizeBytes":{"type":"integer","minimum":1},"checksumSha256":{"type":"string","maxLength":64}}},"MediaUploadSession":{"type":"object","description":"Upload the bytes to this target, then call the complete endpoint.","additionalProperties":true},"MediaStatus":{"type":"object","properties":{"listingId":{"type":"string"},"photos":{"type":"integer"},"videos":{"type":"integer"},"pending":{"type":"integer"},"failed":{"type":"integer"},"items":{"type":"array","items":{"type":"object"}}}},"SubmitRequest":{"type":"object","properties":{"confirmationId":{"type":"string","description":"From the USER_CONFIRMATION_REQUIRED response, after the owner approves."}}},"SubmitResult":{"type":"object","properties":{"listingId":{"type":"string"},"listingNumber":{"type":"integer"},"status":{"type":"string"},"moderation":{"type":"string","const":"standard"}}},"ListingStatus":{"type":"object","properties":{"listingId":{"type":"string"},"listingNumber":{"type":"integer"},"status":{"type":"string"},"rejectionReason":{"type":["string","null"]},"publishedAt":{"type":["string","null"],"format":"date-time"},"moderation":{"type":"string"}}}}}}