Store Credit REST API
Store Credit adds nine web API routes: five admin routes for managing any customer's balance, and four customer routes scoped to the logged-in customer and their own cart. All of them go through the same service contracts the admin screens use, so the ledger, the guards, and the audit trail behave identically.
Admin Routes
These routes need an admin or integration token and are gated by ACL resources, so grant the matching resources to the integration's role.
| Method | Route | Service method | ACL resource |
|---|---|---|---|
GET |
/V1/hyva-store-credit/balance/:customerId/:websiteId |
BalanceManagementInterface::getBalance |
Hyva_StoreCredit::balance_view |
GET |
/V1/hyva-store-credit/history/:customerId |
HistoryRepositoryInterface::getForCustomer |
Hyva_StoreCredit::balance_view |
POST |
/V1/hyva-store-credit/credit |
BalanceManagementInterface::credit |
Hyva_StoreCredit::balance_adjust |
POST |
/V1/hyva-store-credit/debit |
BalanceManagementInterface::debit |
Hyva_StoreCredit::balance_adjust |
POST |
/V1/hyva-store-credit/adjust |
BalanceManagementInterface::adjust |
Hyva_StoreCredit::balance_adjust |
Customer Routes
These use the self resource, so the customer's own token is enough. Store Credit forces the identity from the token rather than reading it from the request, which is why there is no customer ID or cart ID in the payload: a customer cannot ask about anyone else's balance or cart.
| Method | Route | Service method |
|---|---|---|
GET |
/V1/hyva-store-credit/mine/balance/:websiteId |
BalanceManagementInterface::getBalance |
GET |
/V1/carts/mine/store-credit |
QuoteBalanceManagementInterface::getApplicable |
POST |
/V1/carts/mine/store-credit/apply |
QuoteBalanceManagementInterface::apply |
POST |
/V1/carts/mine/store-credit/remove |
QuoteBalanceManagementInterface::remove |
Reading a Balance as an Admin
Fetch a single customer's balance on a website:
curl -X GET "https://example.com/rest/V1/hyva-store-credit/balance/42/1" \
-H "Authorization: Bearer $ADMIN_TOKEN"
The response is a balance object with the customer, the website, the amount, its currency, and when it last changed:
{
"customer_id": 42,
"website_id": 1,
"amount": 487.39,
"base_currency_code": "EUR",
"updated_at": "2026-07-31 09:28:47"
}
Crediting a Customer
credit and debit both take a positive amount and a reason, and both accept an optional source and idempotency key. Send the idempotency key whenever the call could be retried.
curl -X POST "https://example.com/rest/V1/hyva-store-credit/credit" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"customerId": 42,
"websiteId": 1,
"amount": 25.00,
"reason": "Goodwill after support ticket 4412",
"source": "api",
"idempotencyKey": "support-4412-goodwill"
}'
The response is the ledger entry that was written, so you can store entry_id against your own record and read balance_after without a second call:
{
"entry_id": 1204,
"customer_id": 42,
"website_id": 1,
"event_type": 1,
"delta": 25,
"balance_after": 512.39,
"base_currency_code": "EUR",
"reason": "Goodwill after support ticket 4412",
"source": "api",
"idempotency_key": "support-4412-goodwill",
"created_at": "2026-08-18 09:41:02"
}
Repeating that request with the same idempotencyKey returns this same entry rather than crediting another €25.00.
Use adjust instead of credit and debit when your own code already works in signed amounts. It takes a delta that may be negative, and no idempotency key.
Applying Credit to the Customer's Own Cart
Ask how much credit the cart can absorb, which is the balance capped at the cart total:
curl -X GET "https://example.com/rest/V1/carts/mine/store-credit" \
-H "Authorization: Bearer $CUSTOMER_TOKEN"
Then apply it. There is no body, because both the customer and the cart come from the token:
curl -X POST "https://example.com/rest/V1/carts/mine/store-credit/apply" \
-H "Authorization: Bearer $CUSTOMER_TOKEN" \
-H "Content-Type: application/json"
apply and remove return no content on success. They set the store credit fields on the quote, exactly as the storefront panel does, and the balance itself is only debited when the order is placed.
Who Gets Recorded as the Actor
Every write records where it came from. An admin token stamps admin_user_id with the admin user's ID; an integration token stamps api_user with the user type and ID. That is what the By column of the admin credit history reads, so an integration's writes are always distinguishable from a person's.
Errors
Store Credit's exceptions surface as ordinary Magento API errors with their messages intact, so a client can act on them:
- Taking a balance below zero returns "The store credit balance cannot be reduced below zero."
- A currency that does not match the stored balance returns "Store credit is held in [X] and cannot be combined with [Y]."
- A non-positive amount on
creditordebitreturns "The store credit amount must be greater than zero." - A missing reason returns "An internal reason is required for every store credit adjustment."
Related Topics
- Store Credit Service API - the PHP contracts behind these routes, with their exact signatures.
- Store Credit GraphQL API - the storefront-facing alternative for headless builds.
- Importing and Exporting Balances - the file-based route for bulk changes.