Skip to main content
Use POST /v1/customers/deposit to add credits to a user.

Minimal Example

curl -X POST https://api.velobase.io/v1/customers/deposit \
  -H "Authorization: Bearer your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": "user_987",
    "amount": 1000
  }'
If the user does not exist, it will be created automatically.

Add a Wallet Category

Use credit_type when you want this deposit to show up under a specific wallet category in the console and balance breakdown.
curl -X POST https://api.velobase.io/v1/customers/deposit \
  -H "Authorization: Bearer your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": "user_987",
    "amount": 500,
    "credit_type": "promo_campaign_2026",
    "idempotency_key": "deposit_user_987_promo_2026"
  }'
Use any string for credit_type, for example: default, promo_campaign_2026, membership_gold.

Add a Validity Period

Use starts_at and expires_at when these credits should only be usable during a specific time window.
curl -X POST https://api.velobase.io/v1/customers/deposit \
  -H "Authorization: Bearer your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": "user_987",
    "amount": 200,
    "credit_type": "summer_campaign_2026",
    "starts_at": "2026-06-01T00:00:00.000Z",
    "expires_at": "2026-06-30T23:59:59.999Z",
    "idempotency_key": "deposit_user_987_summer_campaign_2026"
  }'
Before starts_at the credits are inactive. After expires_at they are no longer counted.

Parameter Reference

body.customer_id
string
required
Your internal ID for the customer. If the customer does not exist, it is created automatically.
body.amount
number
required
Number of credits to add. Must be greater than 0.
body.credit_type
string
default:"default"
Wallet category for this deposit. Use any string, such as default, promo_campaign_2026, or membership_gold. Defaults to default.
body.starts_at
string
ISO 8601 datetime. Before this time, the deposited credits do not count toward the available balance.
body.expires_at
string
ISO 8601 datetime. After this time, the deposited credits no longer count toward the available balance. Must be later than starts_at.
body.idempotency_key
string
Prevents duplicate deposits. Repeating a request with the same key returns the original result with is_idempotent_replay: true and does not create a second deposit.
body.name
string
Display name for the customer. Created or updated on deposit.
body.email
string
Email address for the customer. Created or updated on deposit.
body.metadata
object
Arbitrary JSON attached to the customer record.
body.description
string
A human-readable note for this deposit.

Deposit Response

{
  "customer_id": "user_987",
  "account_id": "...",
  "credit_type": "summer_campaign_2026",
  "total_amount": 1000,
  "added_amount": 1000,
  "starts_at": "2026-06-01T00:00:00.000Z",
  "expires_at": "2026-06-30T23:59:59.999Z",
  "record_id": "...",
  "is_idempotent_replay": false
}
customer_id
string
The customer ID passed in the request.
account_id
string
The underlying credit account created by this deposit.
credit_type
string
Wallet category used for this deposit.
total_amount
number
Total amount on this credit account record. Not the customer’s overall balance.
added_amount
number
Amount added by this specific request.
starts_at
string
Start time of this credit account’s validity window.
expires_at
string
Expiry time of this credit account’s validity window.
record_id
string
The ledger record ID for this deposit.
is_idempotent_replay
boolean
true when the response was returned from a previous request with the same idempotency_key.

Query Balance and Wallet Categories

curl https://api.velobase.io/v1/customers/user_987 \
  -H "Authorization: Bearer your_api_key_here"
{
  "id": "user_987",
  "name": "Alice",
  "email": "alice@example.com",
  "balance": {
    "total": 1500,
    "used": 0,
    "frozen": 0,
    "available": 1500
  },
  "accounts": [
    {
      "account_type": "CREDIT",
      "credit_type": "default",
      "total": 1000,
      "used": 0,
      "frozen": 0,
      "available": 1000,
      "starts_at": null,
      "expires_at": null
    },
    {
      "account_type": "CREDIT",
      "credit_type": "promo_campaign_2026",
      "total": 500,
      "used": 0,
      "frozen": 0,
      "available": 500,
      "starts_at": null,
      "expires_at": null
    }
  ],
  "created_at": "2026-04-07T12:00:00.000Z"
}
balance.total
number
Sum of all active credit accounts.
balance.used
number
Credits already consumed across all accounts.
balance.frozen
number
Credits currently reserved by in-progress staged deduction flows.
balance.available
number
Credits available to spend: total - used - frozen.
accounts
array
Per-account balance breakdown. Each entry corresponds to one deposit’s credit account, identified by its credit_type.

Error Format

All API errors return an HTTP error status and a structured error object:
{
  "error": {
    "message": "starts_at must be a valid ISO datetime",
    "type": "bad_request",
    "code": "invalid_starts_at"
  }
}
error.message
string
Human-readable description of the error.
error.type
string
High-level error category, such as bad_request.
error.code
string
Stable machine-readable error code for programmatic handling.