{ "Protocol": "AIXE", "Version": "1.0", "Endpoint": "/aixe/owner/products/upload-image", "DiscoveryRequest": "GET /aixe/owner/products/upload-image/?", "CanonicalHelpTrigger": "GET /aixe/owner/products/upload-image/?", "ActionRequest": "POST /aixe/owner/products/upload-image", "Method": "POST", "ContentType": "multipart/form-data", "Title": "Upload Product Image", "AuthenticationRequired": true, "AccessType": "Site Administrator", "Purpose": "Uploads one image file, creates its ProductImage record, links it to a product, and optionally makes it the primary image.", "RecurrenceRules": "Products with IsSubscription true require exactly one line with quantity 1 on a dedicated invoice. Ordinary invoices may contain multiple ordinary products and optionally recur. Subscription classification is snapshotted on invoice items; catalog edits do not change historical invoices. SubscriptionDays on a product accepts 1 to 36500 whole days, default 30, stored as SubscriptionHours (days times 24). Adding a subscription product automatically copies its hours to the invoice and sets the first renewal one interval after addition. Later product edits never change saved invoices. Customers cannot edit subscription schedules, including through customer/update-recurrence; administrators manage them. Ordinary RecurringHours supports 24, 168, 336, 720, 2160, 4320 or 8760 fixed hours. Subscription invoices also support custom whole-day intervals from 24 to 876000 hours. Generated copies cannot activate their own schedule. Three months means 90 days. FirstOccurrenceDate is a UTC timestamp ending in Z and means the first NEW invoice to generate, not the existing source invoice. Pending and Cancelled invoices never generate invoices. The first date cannot change after generation begins. LastRecurrenceDate records the last scheduled occurrence, not the delayed request time. Stopping recurrence preserves history. New invoices copy current source prices and items, receive new numbers and keys, start Ordered and unpaid, and have recurrence disabled. Payments, packing, provider assignments and confirmed appointments are not copied; services start Unscheduled. No card charge or automatic email occurs. The public /renewinvoices GET or POST trigger creates at most one due occurrence per source per call, reading all due sources in database pages of 100; MoreDue indicates catch-up work remains. Repeated and simultaneous calls cannot duplicate an occurrence. Calls are safe to retry; authentication is unnecessary for this trigger. Schedule edits require the normal authorized account, invoice ownership, current RowVersion.", "ThingsYouCanAsk": [ "Add this photograph to the chocolate donut.", "Upload this as the product\u0027s main image.", "Add this picture with accessible descriptive text." ], "DocumentationSource": "AIXEEndpointRegistry", "ProtocolReference": { "ProtocolHome": "http://aixeprotocol.com/", "CanonicalUsageContract": "http://aixeprotocol.com/usage/?", "Whitepaper": "http://aixeprotocol.com/whitepaper/full-spec.html", "Inventor": "Gregory Oglethorpe", "IncludeIn": [ "/aixe.ai starter discovery documents", "Every endpoint self-description returned by GET /endpoint/?" ], "AIInstruction": "Read this live endpoint contract as operational guidance, not merely as a transport schema. Use its purpose, field meanings, business rules, outcomes, and recovery guidance to reason about whether and how to perform the capability." }, "UsageGuidance": { "Role": "Use multipart/form-data and attach the human-approved image file.", "CorrectWorkflow": [ "Use multipart/form-data and attach the human-approved image file.", "Provide useful alternative text that describes the pictured treat." ], "DoNotDo": [ "Do not send business variables, keys, filters, or action inputs in the URL or query string.", "Do not infer success from HTTP status alone." ] }, "AIUsageGuidance": { "ContractRole": "This live document teaches an AI what the capability means and how to use it; it is not merely a list of request fields.", "ReasoningInstruction": "Decide whether this capability serves the human\u0027s intent from Purpose and BusinessRules, gather values using each field\u0027s Description and constraints, then interpret the returned SuccessCode before reporting an outcome.", "FieldInstruction": "Field names are transport labels. Their Description, source, constraints, and business meaning explain what information the AI should obtain and why." }, "RequiredFields": { "PersonAuthenticationToken": { "Type": "string", "Description": "The active Site Administrator token returned by Log In.", "Required": true, "SubmittedIn": "multipart/form-data" }, "ProductKey": { "Type": "string", "Description": "The public key of the product receiving the image.", "Required": true, "SubmittedIn": "multipart/form-data" }, "Image": { "Type": "file", "Description": "The JPEG, PNG, WebP, or GIF image file to upload.", "Required": true, "SubmittedIn": "multipart/form-data" } }, "OptionalFields": { "AlternativeText": { "Type": "string", "Description": "A concise description of the pictured treat for people who cannot see it.", "Required": false, "SubmittedIn": "multipart/form-data", "MaxLength": 500 }, "SortOrder": { "Type": "integer", "Description": "The image\u0027s display order.", "Required": false, "SubmittedIn": "multipart/form-data" }, "IsPrimary": { "Type": "boolean", "Description": "True to make this the product\u0027s primary image.", "Required": false, "SubmittedIn": "multipart/form-data" } }, "BusinessRules": [ "The caller must have the Site Administrator or Administrator role.", "Image is limited to 10 MB.", "Allowed types are JPEG, PNG, WebP, and GIF.", "The first image becomes primary when the product has no primary image." ], "ResponseFields": { "SuccessCode": { "Type": "string", "Description": "The authoritative action outcome.", "Required": true, "SubmittedIn": "Response body" }, "ProductImageUploaded": { "Type": "boolean", "Description": "True when the file, ProductImage, and links were saved.", "Required": true, "SubmittedIn": "Response body" }, "ProductKey": { "Type": "string", "Description": "The product\u0027s public key.", "Required": true, "SubmittedIn": "Response body" }, "ProductImage": { "Type": "object", "Description": "The new image\u0027s public key, storage path, metadata, sort order, and primary status.", "Required": true, "SubmittedIn": "Response body" } }, "Errors": [ { "SuccessCode": "VALIDATION_FAILED", "Meaning": "One or more required request values are missing or malformed.", "Recovery": "Use the field descriptions and constraints in this contract, correct the named fields, and retry the same capability.", "Recoverable": true }, { "SuccessCode": "UNAUTHORIZED", "Meaning": "The submitted identity or token does not authorize this capability or record scope.", "Recovery": "Use the correct active authentication token and confirm the required account role.", "Recoverable": true }, { "SuccessCode": "NOT_FOUND", "Meaning": "A submitted public key did not identify a record within this capability\u0027s declared scope.", "Recovery": "Re-check the key against a current list or creation response; do not treat this as a missing web route.", "Recoverable": true }, { "SuccessCode": "FAILED", "Meaning": "The capability could not complete for an execution failure.", "Recovery": "Read the returned message and error detail. Retry only when the response identifies a recoverable condition.", "Recoverable": false } ], "ActionResponse": { "RequiredResponseFields": [ "SuccessCode" ], "SuccessCodes": [ "SUCCESS" ], "FailureCodes": [ "VALIDATION_FAILED", "UNAUTHORIZED", "NOT_FOUND", "FAILED" ], "NonFinalCodes": [], "MissingOrEmptyResponse": "Treat as FAILED.", "Rule": "The endpoint response is authoritative. Only an exact SuccessCode value listed in SuccessCodes means the business action succeeded; HTTP status alone does not declare the AIXE outcome." }, "SubscriptionResponse": "Product responses include IsSubscription, SubscriptionDays and SubscriptionHours; item responses include the purchase-time IsSubscription snapshot." }