{"openapi":"3.1.0","info":{"title":"CircleLoyal Partners API","version":"2026-09-11-r323","description":"Публичный контракт партнёрской интеграции CircleLoyal: подписанные события, проекция баланса, recap и операции списания CIRCLE. Секреты и боевые ключи выдаются только партнёрам после согласованного пилота."},"servers":[{"url":"https://circleloyal.com","description":"Production CircleLoyal"}],"tags":[{"name":"Partner Events","description":"Подписанные события начислений, отмен и возвратов."},{"name":"Partner Accounts","description":"Безопасные пользовательские проекции Circle ID."},{"name":"Partner Redemptions","description":"Расчёт, резерв, применение и возврат CIRCLE."}],"security":[{"CircleKeyId":[],"CircleTimestamp":[],"CircleNonce":[],"CircleIdempotency":[],"CircleMode":[],"CircleSignature":[]}],"paths":{"/v1/partners/{partner}/events":{"post":{"tags":["Partner Events"],"summary":"Передать партнёрское событие в Circle Ledger","description":"Запрос должен быть подписан backend-сервером партнёра. Повтор того же event_id или Idempotency-Key принимается только при неизменном payload hash.","parameters":[{"$ref":"#/components/parameters/PartnerPath"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerEvent"},"examples":{"stayCompleted":{"$ref":"#/components/examples/StayCompletedEvent"},"taskApproved":{"$ref":"#/components/examples/TaskApprovedEvent"}}}}},"responses":{"200":{"description":"Событие принято или распознано как точный duplicate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerEventResult"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Conflict"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/v1/partners/{partner}/accounts/by-external-user/{externalUserId}/projection":{"get":{"tags":["Partner Accounts"],"summary":"Получить безопасную проекцию Circle ID","parameters":[{"$ref":"#/components/parameters/PartnerPath"},{"$ref":"#/components/parameters/ExternalUserIdPath"}],"responses":{"200":{"description":"Проекция баланса, уровня и статуса связанного Circle ID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountProjection"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/partners/{partner}/accounts/by-external-user/{externalUserId}/daily-recap":{"get":{"tags":["Partner Accounts"],"summary":"Получить краткий итог дня для партнёрского интерфейса","parameters":[{"$ref":"#/components/parameters/PartnerPath"},{"$ref":"#/components/parameters/ExternalUserIdPath"}],"responses":{"200":{"description":"Итог дня, если есть смысл показать пользователю.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DailyRecap"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/partners/shelterz/redemptions/quote":{"post":{"tags":["Partner Redemptions"],"summary":"Предварительно рассчитать доступное списание CIRCLE","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RedemptionQuoteRequest"}}}},"responses":{"200":{"$ref":"#/components/responses/RedemptionResult"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/partners/shelterz/redemptions/reserve":{"post":{"tags":["Partner Redemptions"],"summary":"Зарезервировать CIRCLE для бронирования","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RedemptionBookingRequest"}}}},"responses":{"200":{"$ref":"#/components/responses/RedemptionResult"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Conflict"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/v1/partners/shelterz/redemptions/{action}":{"post":{"tags":["Partner Redemptions"],"summary":"Применить, освободить или вернуть резерв CIRCLE","parameters":[{"name":"action","in":"path","required":true,"schema":{"type":"string","enum":["apply","release","refund"]}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RedemptionTransitionRequest"}}}},"responses":{"200":{"$ref":"#/components/responses/RedemptionResult"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Conflict"},"503":{"$ref":"#/components/responses/Unavailable"}}}}},"components":{"securitySchemes":{"CircleKeyId":{"type":"apiKey","in":"header","name":"X-Circle-Key-Id"},"CircleTimestamp":{"type":"apiKey","in":"header","name":"X-Circle-Timestamp"},"CircleNonce":{"type":"apiKey","in":"header","name":"X-Circle-Nonce"},"CircleIdempotency":{"type":"apiKey","in":"header","name":"Idempotency-Key"},"CircleMode":{"type":"apiKey","in":"header","name":"X-Circle-Mode"},"CircleSignature":{"type":"apiKey","in":"header","name":"X-Circle-Signature","description":"Формат: v1=base64url(HMAC-SHA256(secret, canonicalPayload))."}},"parameters":{"PartnerPath":{"name":"partner","in":"path","required":true,"schema":{"type":"string","enum":["shelterz","moneytasks","booked"]}},"ExternalUserIdPath":{"name":"externalUserId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9:_-]{1,100}$"}}},"schemas":{"PartnerEvent":{"oneOf":[{"$ref":"#/components/schemas/BookingEvent"},{"$ref":"#/components/schemas/TaskApprovedEvent"}]},"BookingEvent":{"type":"object","required":["schema_version","event_id","event_type","occurred_at","partner_id","subject","booking","facts","supersedes_event_id"],"properties":{"schema_version":{"type":"integer","const":1},"event_id":{"type":"string","maxLength":80},"event_type":{"type":"string","enum":["booking.payment_settled","booking.stay_completed","booking.cancelled","booking.refunded","booking.chargeback"]},"occurred_at":{"type":"string","format":"date-time"},"partner_id":{"type":"string","const":"shelterz"},"subject":{"$ref":"#/components/schemas/EventSubject"},"booking":{"$ref":"#/components/schemas/BookingFacts"},"facts":{"$ref":"#/components/schemas/BookingStatusFacts"},"supersedes_event_id":{"type":["string","null"],"maxLength":80}}},"TaskApprovedEvent":{"type":"object","required":["schema_version","event_id","event_type","occurred_at","partner_id","subject","task","supersedes_event_id"],"properties":{"schema_version":{"type":"integer","const":1},"event_id":{"type":"string","maxLength":80},"event_type":{"type":"string","const":"task.approved"},"occurred_at":{"type":"string","format":"date-time"},"partner_id":{"type":"string","const":"moneytasks"},"subject":{"$ref":"#/components/schemas/EventSubject"},"task":{"$ref":"#/components/schemas/TaskFacts"},"supersedes_event_id":{"type":["string","null"],"maxLength":80}}},"EventSubject":{"type":"object","required":["external_user_id"],"properties":{"external_user_id":{"type":"string","maxLength":100},"referral_code":{"type":"string","pattern":"^[A-Z0-9]{8,24}$"}}},"BookingFacts":{"type":"object","required":["external_booking_id","currency","gross_amount_minor","discount_amount_minor","circle_spent_minor","net_cash_paid_minor"],"properties":{"external_booking_id":{"type":"string","maxLength":100},"public_booking_id":{"type":["string","null"],"maxLength":100},"currency":{"type":"string","const":"RUB"},"gross_amount_minor":{"type":"integer","minimum":0},"discount_amount_minor":{"type":"integer","minimum":0},"circle_spent_minor":{"type":"integer","minimum":0},"net_cash_paid_minor":{"type":"integer","minimum":0},"arrival_at":{"type":["string","null"],"format":"date-time"},"departure_at":{"type":["string","null"],"format":"date-time"},"location":{"$ref":"#/components/schemas/BookingLocation"}}},"BookingLocation":{"type":"object","properties":{"city_name":{"type":"string","maxLength":120},"city_key":{"type":["string","null"],"maxLength":140},"country_code":{"type":["string","null"],"pattern":"^[A-Z]{2,3}$"},"region_name":{"type":["string","null"],"maxLength":120}}},"BookingStatusFacts":{"type":"object","required":["payment_status","stay_status"],"properties":{"payment_status":{"type":"string","enum":["pending","settled","refunded","chargeback"]},"stay_status":{"type":"string","enum":["planned","completed","cancelled"]}}},"TaskFacts":{"type":"object","required":["external_task_id","title","circle_amount_minor","xp_amount"],"properties":{"external_task_id":{"type":"string","maxLength":100},"external_order_id":{"type":["string","null"],"maxLength":100},"title":{"type":"string","maxLength":180},"category":{"type":["string","null"],"maxLength":80},"circle_amount_minor":{"type":"integer","minimum":0},"xp_amount":{"type":"integer","minimum":0},"moderated_at":{"type":["string","null"],"format":"date-time"}}},"PartnerEventResult":{"type":"object","required":["status","event_id","mode","account"],"properties":{"status":{"type":"string","enum":["accepted","duplicate"]},"event_id":{"type":"string"},"mode":{"type":"string","enum":["shadow","live"]},"reward":{"type":"object"},"account":{"$ref":"#/components/schemas/AccountProjection"}}},"AccountProjection":{"type":"object","properties":{"account_id":{"type":"string"},"status":{"type":"string"},"balance_minor":{"type":"integer"},"level":{"type":"integer"},"xp":{"type":"integer"}}},"DailyRecap":{"type":"object","properties":{"meaningful":{"type":"boolean"},"items":{"type":"array","items":{"type":"object"}}}},"RedemptionQuoteRequest":{"type":"object","required":["external_user_id","gross_amount_minor"],"properties":{"external_user_id":{"type":"string"},"gross_amount_minor":{"type":"integer","minimum":1},"requested_amount_minor":{"type":"integer","minimum":0}}},"RedemptionBookingRequest":{"allOf":[{"$ref":"#/components/schemas/RedemptionQuoteRequest"},{"type":"object","required":["external_booking_id"],"properties":{"external_booking_id":{"type":"string","maxLength":100}}}]},"RedemptionTransitionRequest":{"type":"object","required":["external_user_id","external_booking_id"],"properties":{"external_user_id":{"type":"string"},"external_booking_id":{"type":"string","maxLength":100}}},"RedemptionResult":{"type":"object","properties":{"mode":{"type":"string","enum":["shadow","live"]},"status":{"type":"string","enum":["eligible","ineligible","shadow","reserved","applied","released","expired","refunded"]},"eligible":{"type":"boolean"},"reason":{"type":["string","null"]},"redemption_id":{"type":["string","null"]},"external_booking_id":{"type":["string","null"]},"gross_amount_minor":{"type":"integer"},"requested_amount_minor":{"type":"integer"},"reserved_amount_minor":{"type":"integer"},"payable_amount_minor":{"type":"integer"},"balance_minor":{"type":"integer"},"available_minor":{"type":"integer"},"expires_at":{"type":["string","null"],"format":"date-time"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}}},"responses":{"BadRequest":{"description":"Неверная схема, сумма, статус или идентификатор.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Unauthorized":{"description":"Отсутствует или не прошла проверку подпись, ключ, timestamp или nonce.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Conflict":{"description":"Конфликт idempotency, replay nonce или несовпадение фактов операции.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"NotFound":{"description":"Партнёр, пользователь или связанная операция не найдены.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Unavailable":{"description":"Ключ или live-контур не настроен; используйте shadow-режим до включения.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"RedemptionResult":{"description":"Результат расчёта или перехода CIRCLE-резерва.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RedemptionResult"}}}}},"examples":{"StayCompletedEvent":{"value":{"schema_version":1,"event_id":"stz_evt_20260911_0001","event_type":"booking.stay_completed","occurred_at":"2026-09-11T09:00:00.000Z","partner_id":"shelterz","subject":{"external_user_id":"7421","referral_code":"CIRCLE2026"},"booking":{"external_booking_id":"stz-booking-94817","public_booking_id":"94817","currency":"RUB","gross_amount_minor":1800000,"discount_amount_minor":0,"circle_spent_minor":0,"net_cash_paid_minor":1800000,"arrival_at":"2026-09-08T14:00:00.000Z","departure_at":"2026-09-11T10:00:00.000Z","location":{"city_name":"Москва","country_code":"RU"}},"facts":{"payment_status":"settled","stay_status":"completed"},"supersedes_event_id":null}},"TaskApprovedEvent":{"value":{"schema_version":1,"event_id":"mt_evt_20260911_0001","event_type":"task.approved","occurred_at":"2026-09-11T09:00:00.000Z","partner_id":"moneytasks","subject":{"external_user_id":"8342"},"task":{"external_task_id":"task-1793","external_order_id":"order-772","title":"Проверенное задание партнёра","category":"research","circle_amount_minor":2500,"xp_amount":120,"moderated_at":"2026-09-11T08:45:00.000Z"},"supersedes_event_id":null}}}},"x-circle-canonical-payload":["METHOD","requestTarget","timestamp","nonce","idempotencyKey","sha256(rawBody)"],"x-circle-privacy":{"forbidden":["passwords","payment-card-data","api-secrets-in-url","unnecessary-personal-data"]},"x-circle-release-readiness":{"status_page":"https://circleloyal.com/partners/api#api-status","changelog":"https://circleloyal.com/partners/api#launch-checklist","signature_test_vector":"https://circleloyal.com/partners/api#signature-test-vector","signature_test_endpoint":"https://circleloyal.com/api/partners/signature-test","self_serve_keys":"planned","pilot_mode":"shadow-first"},"x-circle-signature-test-vector":{"method":"POST","requestTarget":"/v1/partners/shelterz/events","timestamp":"1736539200","nonce":"nonce-4cbb33a5b1f24f0c","idempotencyKey":"booking-stay-completed:stz-demo","rawBody":"{\"ok\":true}","testOnlySigningKey":"circleloyal-demo-signing-key","payloadHash":"4062edaf750fb8074e7e83e0c9028c94e32468a8b6f1614774328ef045150f93","canonicalPayload":"POST\n/v1/partners/shelterz/events\n1736539200\nnonce-4cbb33a5b1f24f0c\nbooking-stay-completed:stz-demo\n4062edaf750fb8074e7e83e0c9028c94e32468a8b6f1614774328ef045150f93","signature":"v1=EP98y55_1CtXBuqxnNr6eK0S3LqWEwQfr9mksGcI74Y"}}