## Conventions - Base URL: {url} - Auth: Bearer token in Authorization header (see Authentication) - Versioning: v1 - Placeholders: - {url}: base API origin - {access_token}: token from token generation endpoint - {member_id}: unique member identifier (e.g., gr_70001) - {amount}: positive integer hearts to credit or debit - {reason}: short audit text - {bit_id}: client correlation ID for the request - {server_bit_id}: server authoritative transaction ID - {new_balance}: integer balance after operation - {occurred_at_iso8601}: UTC timestampx, e.g., 2025-09-04T12:00:00Z ## Authentication – Generate Token - Method: POST - URL: {url}/cdn/v1/generate/token - Body: none - Required headers: - client_id: {client_id} - oneapp_token: {oneapp_token} #### cURL ```bash curl -X POST '{url}/cdn/v1/generate/token' \ -H 'client_id: {client_id}' \ -H 'oneapp_token: {oneapp_token}' ``` #### Success response ```json { "access_token": "{access_token}", "expires_in": {expires_in_seconds}, "refresh_expires_in": {refresh_expires_in_seconds}, "refresh_token": {refresh_token_or_null}, "token_type": "{token_type}", "id_token": "{id_token}", "not-before-policy": {not_before_epoch_seconds}, "session_state": {session_state_or_null}, "scope": "{scope}" } ``` #### Status codes | HTTP | Meaning | |---|---| | 200 | Token issued; use access_token until expires_in | | 400 | Missing/invalid headers (client_id/oneapp_token) | | 401 | Invalid credentials | | 403 | Client recognized but not permitted to generate tokens | | 429 | Rate limited | | 500 | Server error | ## Balance Check - Method: GET - URL: {url}/v1/members/{member_id}/balances - Required headers: - Authorization: Bearer {access_token} - Content-Type: application/json #### cURL ```bash curl -X GET '{url}/v1/members/{member_id}/balances' \ -H 'Authorization: Bearer {access_token}' \ -H 'Content-Type: application/json' ``` #### Success response ```json { "success": true, "message": "Balance retrieved.", "data": { "memberId": "{member_id}", "balances": { "hearts": {hearts_balance} } } } ``` #### Error response (example) ```json { "success": false, "error": { "code": "MEMBER_NOT_FOUND", "httpStatus": 404, "message": "Member not found." } } ``` #### Status codes | HTTP | Meaning | |---|---| | 200 | Balance returned | | 400 | Bad path parameter (member_id) | | 401 | Missing/invalid Authorization | | 404 | Member not found | | 500 | Server error | ## Give Hearts (Credit) - Method: POST - URL: {url}/v1/hearts/credits - Required headers: - Authorization: Bearer {access_token} - Content-Type: application/json - Request body: - memberId: {member_id} - amount: {amount} (positive integer) - reason: {reason} - bitId: {bit_id} - metadata: optional object (e.g., {"source":"{source}"}) #### cURL ```bash curl -X POST '{url}/v1/hearts/credits' \ -H 'Authorization: Bearer {access_token}' \ -H 'Content-Type: application/json' \ -d '{ "memberId": "{member_id}", "amount": {amount}, "reason": "{reason}", "bitId": "{bit_id}", "metadata": { "source": "{source}" } }' ``` #### Success response ```json { "success": true, "message": "Hearts credited.", "data": { "bitId": "{server_bit_id}", "memberId": "{member_id}", "transaction": { "type": "credit", "amount": {amount}, "heartsAdded": {amount}, "heartsDeducted": 0, "newBalance": {new_balance}, "occurredAt": "{occurred_at_iso8601}" } } } ``` #### Error response (examples) - Validation ```json { "success": false, "error": { "code": "VALIDATION_ERROR", "httpStatus": 400, "message": "amount must be a positive integer." } } ``` - Authorization ```json { "success": false, "error": { "code": "UNAUTHORIZED", "httpStatus": 401, "message": "Missing or invalid token." } } ``` #### Status codes | HTTP | Meaning | |---|---| | 200 | Credit applied | | 400 | Validation error (e.g., amount <= 0, malformed JSON) | | 401 | Missing/invalid Authorization | | 404 | Member not found | | 500 | Server error | ## Deduct Hearts (Debit) - Method: POST - URL: {url}/v1/hearts/debits - Required headers: - Authorization: Bearer {access_token} - Content-Type: application/json - Request body: - memberId: {member_id} - amount: {amount} (positive integer; must be <= available balance) - reason: {reason} - bitId: {bit_id} - metadata: optional object (e.g., {"source":"{source}"}) #### cURL ```bash curl -X POST '{url}/v1/hearts/debits' \ -H 'Authorization: Bearer {access_token}' \ -H 'Content-Type: application/json' \ -d '{ "memberId": "{member_id}", "amount": {amount}, "reason": "{reason}", "bitId": "{bit_id}", "metadata": { "source": "{source}" } }' ``` #### Success response ```json { "success": true, "message": "Hearts debited.", "data": { "bitId": "{server_bit_id}", "memberId": "{member_id}", "transaction": { "type": "debit", "amount": {amount}, "heartsAdded": 0, "heartsDeducted": {amount}, "newBalance": {new_balance}, "occurredAt": "{occurred_at_iso8601}" } } } ``` #### Error response (examples) - Business rule ```json { "success": false, "error": { "code": "INSUFFICIENT_BALANCE", "httpStatus": 400, "message": "Insufficient balance." } } ``` - Validation ```json { "success": false, "error": { "code": "VALIDATION_ERROR", "httpStatus": 400, "message": "amount must be a positive integer." } } ``` #### Status codes | HTTP | Meaning | |---|---| | 200 | Debit applied | | 400 | Validation/business error (e.g., insufficient balance) | | 401 | Missing/invalid Authorization | | 404 | Member not found | | 500 | Server error | ### Validation Rules - amount must be a positive integer for both credit and debit. - Debit amount must not exceed current hearts balance. - bitId is a client correlation ID; the server returns an authoritative bitId in data.bitId. - memberId must identify an existing member.