Client Credit

11 Aufrufe Markdown

The five endpoints that read a client's prepaid balance, adjust it and wire it to automatic payment.

Overview

Credit is the prepaid balance sitting on a client's account. These endpoints manage the manual adjustments to it; money taken by a payment provider does not come through here.

Every record carries a direction: up raises the balance, down lowers it. The amount is always positive.

Reference

Listing Credit Records

get/api/v1/admin/clients/{id}/credits
Clients/GetClientCredits admin

Returns the ledger of manual adjustments made to the client's balance.

Response fields data[] — 7
idintId of the credit record.
typestringup raises the balance, down lowers it.
amountnumberAmount. Rounded to two decimals and always positive; the direction is carried by type.
currency_idintCurrency id of the record.
descriptionstringDescription.
added_byintId of the admin who added it.
created_atstringCreation time.
Errors 2
not_found404No such client or credit record.
insufficient_scope403The key lacks the required scope.
Request
curl 'https://panel.example.com/api/v1/admin/clients/42/credits' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch('https://panel.example.com/api/v1/admin/clients/42/credits', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/42/credits');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Clients()->GetClientCredits(['id' => 42]);

$added = 0.0;
foreach ($response['data'] as $entry) {
    if ($entry['type'] === 'up') {
        $added += (float) $entry['amount'];
    }
}

Adding Credit

post/api/v1/admin/clients/{id}/credits
Clients/CreateClientCredit admin moves the balance

Writes a manual adjustment to the balance and returns the balance after it.

Body 3
typestringrequiredup or down.
amountnumberrequiredMust be greater than zero. Read in the client's balance currency.
descriptionstringDescription. It shows in the ledger.
Response fields data — 2
creditobjectThe record that was created, in the same schema as the list.
new_balancenumberThe balance after the adjustment.
Errors 4
not_found404No such client or credit record.
type_invalid422type is neither up nor down.
amount_invalid422The amount is zero or negative.
insufficient_scope403The key lacks the required scope.
Request
curl -X POST 'https://panel.example.com/api/v1/admin/clients/42/credits' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"type":"up","amount":50,"description":"Manual top-up"}'
const res = await fetch('https://panel.example.com/api/v1/admin/clients/42/credits', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({"type":"up","amount":50,"description":"Manual top-up"}),
});

const body = await res.json();
console.log(body.data.new_balance);
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/42/credits');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'type'        => 'up',
        'amount'      => 50,
        'description' => 'Manual top-up',
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Clients()->CreateClientCredit([
    'id'          => 42,
    'type'        => 'up',
    'amount'      => 50,
    'description' => 'Manual top-up',
]);

$balance = $response['data']['new_balance'] ?? null;
Response
{
  "data": {
    "credit": {
      "id": 10,
      "type": "up",
      "amount": 50.00,
      "currency_id": 1,
      "description": "Manual top-up",
      "added_by": 1,
      "created_at": "2026-06-21 12:00:00"
    },
    "new_balance": 150.00
  }
}
{
  "error": {
    "code": "amount_invalid",
    "message": "Amount must be greater than zero."
  }
}

Updating a Credit Record

patch/api/v1/admin/clients/{id}/credits/{log_id}
Clients/UpdateClientCredit admin

Corrects an existing record. If the amount or the direction changes, the balance is recalculated.

Body at least one
typestringup or down.
amountnumberAn amount greater than zero.
descriptionstringDescription.
Response fields data — 2
creditobjectThe updated record, in the same schema as the list.
new_balancenumberThe recalculated balance.
Errors 4
not_found404No such client or credit record.
type_invalid422type is neither up nor down.
amount_invalid422The amount is zero or negative.
insufficient_scope403The key lacks the required scope.
Request
curl -X PATCH 'https://panel.example.com/api/v1/admin/clients/42/credits/10' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"amount":75}'
const res = await fetch('https://panel.example.com/api/v1/admin/clients/42/credits/10', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ amount: 75 }),
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/42/credits/10');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PATCH',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['amount' => 75]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Clients()->UpdateClientCredit([
    'id'     => 42,
    'log_id' => 10,
    'amount' => 75,
]);

Deleting a Credit Record

delete/api/v1/admin/clients/{id}/credits/{log_id}
Clients/DeleteClientCredit admin reverses the balance

Deletes the record and reverses its effect on the balance.

Response fields data — 3
deletedboolWhether the delete succeeded.
idintThe deleted credit record's ID.
new_balancenumberThe balance after the reversal.
Errors 2
not_found404No such client or credit record.
insufficient_scope403The key lacks the required scope.
Request
curl -X DELETE 'https://panel.example.com/api/v1/admin/clients/42/credits/10' \
  -H "Authorization: Bearer $API_KEY"
const res = await fetch('https://panel.example.com/api/v1/admin/clients/42/credits/10', {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/42/credits/10');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'DELETE',
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Clients()->DeleteClientCredit([
    'id'     => 42,
    'log_id' => 10,
]);

Paying Automatically from Credit

put/api/v1/admin/clients/{id}/credit-autopay
Clients/SetClientCreditAutopay admin

Sets whether invoices are paid from the balance without asking.

Body 1
enabledboolrequiredWhen on, a due invoice is taken from the balance.
Response fields data
enabledboolThe auto-pay state after the call.
Errors 2
not_found404No such client.
insufficient_scope403The key lacks the required scope.
Request
curl -X PUT 'https://panel.example.com/api/v1/admin/clients/42/credit-autopay' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"enabled":true}'
const res = await fetch('https://panel.example.com/api/v1/admin/clients/42/credit-autopay', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ enabled: true }),
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/42/credit-autopay');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PUT',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['enabled' => true]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Clients()->SetClientCreditAutopay([
    'id'      => 42,
    'enabled' => true,
]);

Pitfalls

Deleting reverses the balance

Deleting a record does not only remove the line; the amount comes back out of the balance. Closing a wrong adjustment with a second record in the opposite direction leaves a clearer trail.

The amount is read in the client's currency

The number you send is in the client's balance currency; the request carries no currency. An integration working across currencies has to convert on its own side.

Autopay does not reach the past

Turning it on does not pay the invoices already waiting; it applies to the ones that fall due afterwards.

War das hilfreich?

Vielen Dank für Ihre Rückmeldung!

Brauchen Sie weitere Hilfe?

Unser Support-Team ist rund um die Uhr für Sie da, wenn Sie oben nicht fündig werden.