← Back to API Docs

Customers

Create a customer and deposit wallets

Create a Customer with a UUID ref_id, receive long-lived deposit addresses, and credit your own user ledger on deposit.credited.

Create a customer and deposit wallets

Use the Customers rail when end users in your app need long-lived deposit addresses (and later withdrawals). This is different from Checkout, which creates a one-time payment session.

Prerequisites: Getting started (Secret key + Request-Id) and Webhooks.

User signs up in your app
  → your server POST /v1/customers
  → show wallets[].address to the user
User sends USDC/USDT on-chain
  → Doggie Pay credits your merchant pool
  → webhook deposit.credited
  → you credit that user's balance in your system

1. Who does what

ConcernDoggie PayYour system
User identityCustomer with ref_id (your user UUID)Accounts, KYC, risk
Deposit addressLong-lived per chain (issued on create)Display & bind to your user
On-chain creditCredits your merchant crypto balance—
End-user balanceNot storedCredit from deposit.credited
Secret / webhookSecret key + merchant webhookKeep Secret server-side; verify HMAC

Do not use Publishable keys or Portal JWT on these Integration routes.

2. Create a customer

POST /v1/customers
Auth: Secret + X-DoggiePay-Request-Id

Request body

FieldTypeRequiredDescription
ref_idstring (UUID)YesYour user id. Immutable after create. Must be a UUID.
namestringYesDisplay name
emailstringYesEmail
descriptionstringNoFree-form note
blockchainsstring[]NoChain aliases to open; omit = all platform-enabled chains

Example

curl -sS https://api.doggiepay.com/v1/customers \
  -H "Authorization: Bearer dp_live_sk_YOUR_SECRET" \
  -H "X-DoggiePay-Request-Id: $(uuidgen | tr '[:upper:]' '[:lower:]')" \
  -H "Content-Type: application/json" \
  -d '{
    "ref_id": "6ded84e7-5449-4a2b-9c1d-0afcce047b29",
    "name": "John Doe",
    "email": "[email protected]",
    "description": "optional note"
  }'

Response data (shape)

FieldTypeDescription
iduuidDoggie Pay customer id
ref_iduuidYour user id (echo)
name / email / descriptionstringProfile fields
walletsarrayDeposit addresses (see below)
created_at / updated_atstringISO-8601

Each wallets[] item:

FieldTypeDescription
blockchainstringChain alias, e.g. ETH
currencystringe.g. USDC, USDT
addressstringDeposit address
statusstringe.g. active

Same chain often shares one address across currencies; rows are expanded per currency for UI convenience.

Wallets are created in the same request. If wallet provisioning fails, the whole create fails (no half-created customer without addresses).

Persist id, ref_id, and the addresses you show to users. For all later deposit/withdraw APIs, pass this ref_id string as external_user_id.

Create errors

HTTPerror.codeMeaning
400ref_id_requiredMissing ref_id
400invalid_ref_idNot a UUID
409customer_ref_id_conflictref_id already used for this merchant
400no_enabled_chainsNo enabled chains
429rate_limitedCreate rate limit (check Retry-After)
429customer_quota_exceededMerchant customer quota exceeded
503 / 502circle_not_configured / circle_errorWallet rail unavailable

3. Look up and update

All require Secret + Request-Id.

MethodPathNotes
GET/v1/customers/{id}Detail + existing wallets (does not auto-open new chains)
GET/v1/customers?ref_id={uuid}Lookup when you only stored ref_id
GET/v1/customers?page=1&per_page=20List; per_page max 100; list items usually omit full wallets
PATCH/v1/customers/{id}Update name / email / description only — not ref_id

List data shape:

{
  "items": [{ "id": "…", "ref_id": "…", "name": "…", "email": "…" }],
  "meta": { "page": 1, "per_page": 20, "total": 42 }
}

4. Ensure / list wallets later

When the platform enables a new chain, or you need to refresh addresses:

MethodPathBody / notes
POST/v1/wallets/ensure{ "external_user_id": "<ref_id>", "blockchains": ["ETH"] } — blockchains optional
GET/v1/wallets/{external_user_id}List existing long-lived addresses (external_user_id = ref_id)

5. When the user deposits

User transfers to wallets[].address
  → Doggie Pay matches the address
  → credits your merchant pool
  → POST your webhook: type = deposit.credited
  → you credit local balance for data.external_user_id (= ref_id)
PracticeDetail
Source of truthTreat deposit.credited as credited — not only a block explorer
IdempotencyDeliveries may retry; key off event id or business keys
Circle webhooksYou do not receive Circle webhooks directly

Typical deposit.credited data fields: deposit_id, amount, currency, external_user_id, blockchain, tx_hash, circle_tx_id, …

Signature and envelope: see Webhooks.

6. Recommended habits

  1. Use a stable UUID as ref_id (maintain a mapping table if your internal id is not a UUID).
  2. On timeout, retry create with the same Request-Id and same JSON body.
  3. Never put Secret keys in the client.
  4. Next: Withdraw for a user.