Pientegra API
Backend-to-Backend API

Create Deposit Intent

Create a deposit intent for a user with POST /external/deposits.

Create intent -> return depositUrl -> signed result webhook

Create intent -> return depositUrl -> signed result webhook

POST /api/v1/external/deposits

This endpoint belongs to the Backend-to-Backend API category. When a user starts a deposit, the partner site calls this endpoint server-side. Pientegra reserves an eligible account, creates a transfer intent, and returns a signed depositUrl to show to the user.

The final decision is not returned synchronously. After the user completes the payment, the deposit is approved or rejected and the result is delivered to the site backend by webhook.

For the user redirection model, see Hosted Deposit Page.

Headers

HeaderRequiredDescription
AuthorizationYesAPI key in Bearer <raw-api-key> format.
Idempotency-KeyYesUnique UUID v4/v7 for this create operation.
Content-TypeYesapplication/json

Request body

{
  "externalUserId": "user-12345",
  "externalUserLabel": "Alex M.",
  "amount": "100000",
  "currency": "TRY"
}
FieldTypeRequiredDescription
externalUserIdstringYesUser ID on the partner site.
externalUserLabelstringNoShort human-readable label for this user in Pientegra, primarily for support conversations. Maximum 128 characters.
amountstring or numberYesDeposit amount in minor units. 100000 = 1,000.00 TRY. Accepted range: 100 (1 TRY) to 100_000_000 (1,000,000 TRY). Values outside this range are rejected with amount_below_min or amount_above_max.
currencystringNoDefaults to TRY. The currently active currency is TRY.

Response

{
  "intentId": "01927b3c-9c1f-7a3a-9c4f-8a3e1f8b1c00",
  "referenceNo": "D-2026-0000123",
  "depositUrl": "https://pay.tenant.example/d/eyJhbGciOi...",
  "requestedAmount": "100000",
  "amount": "100000",
  "currency": "TRY",
  "expiresAt": "2026-04-28T12:30:00.000Z"
}
FieldDescription
intentIdStable UUID for the deposit intent. Used in status lookup and webhook payloads.
referenceNoShort, human-readable reference searchable in support conversations and within Pientegra.
depositUrlSigned one-time URL to open for the user.
requestedAmountOriginal amount posted by the partner. Immutable.
amountCurrent approved amount. If adjusted to the actual received transfer amount, it may differ from requestedAmount; this is the amount to credit to the user balance.
currencyISO 4217 currency code.
expiresAtUTC timestamp when the deposit URL expires. The default token TTL is 30 minutes.

Browser handoff

The hosted deposit page is shown to the user in the browser. If you use a popup, open it during the user interaction and then set its location from the backend response.

Popup-safe handoff
async function startDeposit(amount: string) {
  const popup = window.open('about:blank', '_blank');
  if (!popup) throw new Error('popup_blocked');

  try {
    const response = await fetch('/api/pientegra/deposit', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ amount }),
    });

    const body = await response.json();
    popup.location = body.depositUrl;
  } catch (error) {
    popup.close();
    throw error;
  }
}

Your backend uses the Pientegra API key inside /api/pientegra/deposit. The API key is never sent to the browser.

Status lifecycle

RESERVED
  |-- PENDING_REVIEW
  |    |-- APPROVED
  |    `-- REJECTED
  |-- AUTO_CANCELLED
  `-- LATE_ARRIVAL
       |-- APPROVED
       `-- REJECTED
StatusMeaning
RESERVEDIntent created, account reservation is active, and the user is expected to pay.
PENDING_REVIEWFunds arrived and are under review.
APPROVEDDeposit approved. The site should credit the user balance from this event.
REJECTEDDeposit rejected.
AUTO_CANCELLEDThe user did not pay before expiresAt.
LATE_ARRIVALFunds arrived after expiry and require manual review.

Webhook action

The primary signal for the site balance is the intent.approved webhook. intent.created and intent.auto_cancelled are usually used only for logs or support visibility.

The intent.approved webhook carries both requestedAmount and amount. Always credit the user balance with amount, which is the approved amount actually received. If amount !== requestedAmount, log the discrepancy on the partner side and make it visible to support.

Error cases

HTTPerrorTypical cause
400validation_failedRequired field is missing, amount format is invalid, or partner provisioning is incomplete.
401unauthorizedAPI key is invalid, inactive, or expired.
409idempotency_key_reuse_with_different_bodyThe same key was reused with a different body.
409duplicate_idempotency_keyA request with the same key is still in-flight.
409collateral_exceededPartner collateral is not sufficient for the deposit reservation.
503all_accounts_cappedNo eligible active account capacity remains.
429rate_limitedRate limit exceeded.

For the full list, see Error Reference.

On this page