{"openapi":"3.1.0","info":{"title":"Fluxora Partner Sandbox API","version":"0.1.0","description":"Proposed test integration contract for Goldex/onix. Local sandbox; no live partner connection, money movement, settlement or production ledger. Partner agreement and an externally reachable HTTPS deployment are required before external testing. Operator APIs are separate and are not part of this partner contract."},"servers":[{"url":"https://fluxora.one"}],"security":[{"ProviderApiKey":[]}],"tags":[{"name":"Orders"},{"name":"Events"},{"name":"Receipts"},{"name":"Availability"}],"paths":{"/api/v1/integrations/{provider}/orders":{"post":{"tags":["Orders"],"operationId":"createOrder","summary":"Deliver an order offer","parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","enum":["goldex","onix"]}},{"name":"Webhook-Id","in":"header","required":true,"description":"Stable unique request/event ID. Reuse it and the exact body on retry; use a fresh timestamp/signature.","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{8,100}$"}},{"name":"Webhook-Timestamp","in":"header","required":true,"description":"Unix seconds, tolerance ±300 seconds.","schema":{"type":"string"}},{"name":"Webhook-Signature","in":"header","required":true,"description":"v1,<base64(HMAC-SHA256(UTF8 signing_secret, webhook_id + \".\" + timestamp + \".\" + exact_body))>","schema":{"type":"string"}}],"description":"Authenticate BEFORE idempotency lookup. A successful response means the offer was durably stored, not accepted or paid. Same provider + external_id is unique permanently. Same external_id with different validated data: 409. Same Webhook-Id with a different exact request body: 409. New Webhook-Id + identical order: 200. Retrying after pause/expiry still returns the original result if the original request succeeded. On a network error retry the same Webhook-Id/body with a fresh timestamp; confirm current state with GET.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrder"},"example":{"external_id":"10da8a3c-d929-49c0-bd93-cc570e81ca69","amount":"12500.00","currency":"RUB","payment_details":{"bank":"Тестовый банк","recipient":"Тестовый получатель","card":"TEST-ONLY-0000-0000","phone":"+7 (000) 000-00-00"},"expires_at":"2026-10-29T23:39:33.269Z","receipt_rules":{"content_types":["application/pdf"],"max_size_bytes":10485760,"max_files":2}}}}},"responses":{"200":{"description":"Current order snapshot. server_time is UTC; read the order again after replay to get the latest version.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Order"},"meta":{"type":"object","properties":{"idempotency_replayed":{"type":"boolean"}}}}}}}},"201":{"description":"Current order snapshot. server_time is UTC; read the order again after replay to get the latest version.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Order"},"meta":{"type":"object","properties":{"idempotency_replayed":{"type":"boolean"}}}}}}}},"400":{"description":"Invalid JSON","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid key/signature or expired signature","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict / invalid transition / reception paused","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Offer expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Unsupported content type","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"tags":["Orders"],"operationId":"listOrders","summary":"Reconcile your orders","parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","enum":["goldex","onix"]}},{"name":"after","in":"query","schema":{"type":"integer","minimum":0,"default":0}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}}],"description":"Ascending creation cursor. next_after advances through created orders; it does not track updates. For reconciliation, reread the whole list starting at after=0, or GET a specific external_id. Updates are delivered by callback.","responses":{"200":{"description":"Orders owned by this provider only.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Order"}},"meta":{"type":"object","properties":{"next_after":{"type":"integer"},"server_time":{"type":"string","format":"date-time"}}}}}}}},"401":{"description":"Invalid key/signature or expired signature","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/integrations/{provider}/orders/{external_id}":{"get":{"tags":["Orders"],"operationId":"getOrder","summary":"Get current status by the ORIGINAL full external UID","parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","enum":["goldex","onix"]}},{"name":"external_id","in":"path","required":true,"schema":{"type":"string","maxLength":100}}],"responses":{"200":{"description":"Current order snapshot. server_time is UTC; read the order again after replay to get the latest version.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Order"},"meta":{"type":"object","properties":{"idempotency_replayed":{"type":"boolean"}}}}}}}},"401":{"description":"Invalid key/signature or expired signature","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/integrations/{provider}/events":{"post":{"tags":["Events"],"operationId":"sendEvent","summary":"Confirm completion, cancel an order, or validate a receipt","parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","enum":["goldex","onix"]}},{"name":"Webhook-Id","in":"header","required":true,"description":"Stable unique request/event ID. Reuse it and the exact body on retry; use a fresh timestamp/signature.","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{8,100}$"}},{"name":"Webhook-Timestamp","in":"header","required":true,"description":"Unix seconds, tolerance ±300 seconds.","schema":{"type":"string"}},{"name":"Webhook-Signature","in":"header","required":true,"description":"v1,<base64(HMAC-SHA256(UTF8 signing_secret, webhook_id + \".\" + timestamp + \".\" + exact_body))>","schema":{"type":"string"}}],"description":"provider_version starts at 1 on order creation and must strictly increase per external_id. Retries reuse Webhook-Id and the exact body. New event ID with an already applied/older provider_version: 409 STALE_EVENT. Completion is accepted only from AWAITING_CONFIRMATION. Cancellation is accepted in any non-terminal state. Rejected receipts remain in the audit; rejection from AWAITING_CONFIRMATION returns the order to PROCESSING. No event is echoed back as a callback. Terminal state correction requires manual reconciliation in this MVP.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerEvent"},"example":{"external_id":"10da8a3c-d929-49c0-bd93-cc570e81ca69","type":"order.completed","provider_version":2}}}},"responses":{"200":{"description":"Current order snapshot. server_time is UTC; read the order again after replay to get the latest version.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Order"},"meta":{"type":"object","properties":{"idempotency_replayed":{"type":"boolean"}}}}}}}},"400":{"description":"Invalid JSON","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid key/signature or expired signature","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict / invalid transition / reception paused","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Offer expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Unsupported content type","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/integrations/{provider}/receipts/{receipt_id}/file":{"get":{"tags":["Receipts"],"operationId":"downloadReceipt","summary":"Download a receipt from your own order","parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","enum":["goldex","onix"]}},{"name":"receipt_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Original file bytes; no public or permanent anonymous file URL.","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/png":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"Invalid key/signature or expired signature","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/integrations/{provider}/availability":{"get":{"tags":["Availability"],"operationId":"getAvailability","summary":"Check reception/capacity before sending a new order","parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","enum":["goldex","onix"]}}],"responses":{"200":{"description":"Global operator capacity. A later create can still return 409 if capacity changes.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"enabled":{"type":"boolean"},"can_accept":{"type":"boolean"},"active_orders":{"type":"integer"},"max_active_orders":{"type":"integer"},"version":{"type":"integer"},"server_time":{"type":"string","format":"date-time"}}},"meta":{"type":"object","properties":{"idempotency_replayed":{"type":"boolean"}}}}}}}},"401":{"description":"Invalid key/signature or expired signature","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"webhooks":{"partnerCallback":{"post":{"summary":"Platform → partner configured callback URL","security":[],"parameters":[{"name":"Webhook-Id","in":"header","required":true,"description":"Stable unique request/event ID. Reuse it and the exact body on retry; use a fresh timestamp/signature.","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{8,100}$"}},{"name":"Webhook-Timestamp","in":"header","required":true,"description":"Unix seconds, tolerance ±300 seconds.","schema":{"type":"string"}},{"name":"Webhook-Signature","in":"header","required":true,"description":"v1,<base64(HMAC-SHA256(UTF8 signing_secret, webhook_id + \".\" + timestamp + \".\" + exact_body))>","schema":{"type":"string"}}],"description":"Use the separate callback_secret to verify the same signature formula against the exact raw body. The configured URL is not accepted from an order payload. event_id/Webhook-Id and body remain stable over retries; timestamp/signature change. Persist/deduplicate by event_id before returning any 2xx. Delivery is at least once and not guaranteed to be ordered: apply version only if newer; use GET for reconciliation. Callback failures do not roll back operator actions. 8 attempts, delays 1,2,4,8,16,32,60 seconds; 5-second timeout per attempt. Redirects are not followed. After 8 failures manual retry preserves event_id. These short retry windows are for the sandbox; agree production retention/backoff separately.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Callback"}}}},"responses":{"2XX":{"description":"Durably recorded, including duplicate events."}}}}},"components":{"securitySchemes":{"ProviderApiKey":{"type":"http","scheme":"bearer","description":"Separate opaque api_key for each provider. Never use an operator token or share it with another provider."}},"schemas":{"CreateOrder":{"type":"object","additionalProperties":false,"required":["external_id","amount","currency","payment_details","expires_at","receipt_rules"],"properties":{"external_id":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,100}$"},"amount":{"type":"string","pattern":"^(?:0|[1-9]\\d{0,11})(?:\\.\\d{1,8})?$","description":"Positive decimal string. Do not send a JSON number."},"currency":{"type":"string","pattern":"^[A-Z]{3,8}$"},"payment_details":{"type":"object","additionalProperties":false,"required":["bank","recipient"],"properties":{"bank":{"type":"string","maxLength":200},"recipient":{"type":"string","maxLength":200},"card":{"type":"string","maxLength":200},"phone":{"type":"string","maxLength":200},"account":{"type":"string","maxLength":200}},"anyOf":[{"required":["card"]},{"required":["phone"]},{"required":["account"]}]},"expires_at":{"type":"string","format":"date-time","description":"Deadline to ACCEPT a NEW offer, UTC ISO8601 ending in Z. Accepted orders are not auto-cancelled at this deadline."},"receipt_rules":{"$ref":"#/components/schemas/ReceiptRules"}}},"ReceiptRules":{"type":"object","additionalProperties":false,"required":["content_types","max_size_bytes","max_files"],"properties":{"content_types":{"type":"array","minItems":1,"uniqueItems":true,"items":{"type":"string","enum":["application/pdf","image/jpeg","image/png"]}},"max_size_bytes":{"type":"integer","minimum":1,"maximum":10485760},"max_files":{"type":"integer","minimum":1,"maximum":10}}},"Receipt":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"filename":{"type":"string"},"content_type":{"type":"string"},"size":{"type":"integer"},"sha256":{"type":"string"},"status":{"type":"string","enum":["UPLOADED","ACCEPTED","REJECTED"]},"created_at":{"type":"string","format":"date-time"},"url":{"type":"string","format":"uri"}}},"Order":{"type":"object","properties":{"external_id":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,100}$"},"amount":{"type":"string","pattern":"^(?:0|[1-9]\\d{0,11})(?:\\.\\d{1,8})?$","description":"Positive decimal string. Do not send a JSON number."},"currency":{"type":"string","pattern":"^[A-Z]{3,8}$"},"payment_details":{"type":"object","additionalProperties":false,"required":["bank","recipient"],"properties":{"bank":{"type":"string","maxLength":200},"recipient":{"type":"string","maxLength":200},"card":{"type":"string","maxLength":200},"phone":{"type":"string","maxLength":200},"account":{"type":"string","maxLength":200}},"anyOf":[{"required":["card"]},{"required":["phone"]},{"required":["account"]}]},"expires_at":{"type":"string","format":"date-time","description":"Deadline to ACCEPT a NEW offer, UTC ISO8601 ending in Z. Accepted orders are not auto-cancelled at this deadline."},"receipt_rules":{"$ref":"#/components/schemas/ReceiptRules"},"id":{"type":"string","format":"uuid"},"provider":{"type":"string","enum":["goldex","onix"]},"status":{"type":"string","enum":["NEW","ACCEPTED","PROCESSING","AWAITING_CONFIRMATION","COMPLETED","CANCELLED","EXPIRED"]},"version":{"type":"integer","minimum":1,"description":"Platform revision; separate from partner sequence provider_version."},"provider_version":{"type":"integer","minimum":1},"available_actions":{"type":"array","items":{"type":"string"}},"receipts":{"type":"array","items":{"$ref":"#/components/schemas/Receipt"}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"server_time":{"type":"string","format":"date-time"}}},"PartnerEvent":{"type":"object","additionalProperties":false,"required":["external_id","type","provider_version"],"properties":{"external_id":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,100}$"},"type":{"type":"string","enum":["order.completed","order.cancelled","receipt.accepted","receipt.rejected"]},"provider_version":{"type":"integer","minimum":2},"receipt_id":{"type":"string","format":"uuid"},"reason":{"type":"string","maxLength":500}},"allOf":[{"if":{"properties":{"type":{"enum":["receipt.accepted","receipt.rejected"]}}},"then":{"required":["receipt_id"]}}]},"Callback":{"type":"object","required":["event_id","type","provider","external_id","order_id","status","version","created_at","data"],"properties":{"event_id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["order.accepted","order.processing","receipt.uploaded","order.completion_requested","order.refused","order.expired"]},"provider":{"type":"string"},"external_id":{"type":"string"},"order_id":{"type":"string","format":"uuid"},"status":{"$ref":"#/components/schemas/Order/properties/status"},"version":{"type":"integer"},"created_at":{"type":"string","format":"date-time"},"data":{"type":"object","description":"receipt_id for uploads; receipts metadata array for completion requests. File URLs require provider bearer authentication."}}},"Error":{"type":"object","required":["error","request_id"],"properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}},"request_id":{"type":"string","format":"uuid"}}}}}}