Skip to main content
Danipa
Docs · 009 / 010

SDKs overview

Official Danipa Pay SDKs — Node.js, PHP, Python, Java — with installation, authentication, the minimum end-to-end snippet, and common operation patterns for each.

This page lists the official Danipa Pay SDKs and shows the minimum "make an authenticated call" snippet for each. Pick the SDK for your language; the calls and behaviour are identical to the REST API documented elsewhere.

If your language isn't listed, fall back to the REST API directly — every SDK is a thin wrapper.

Available SDKs

LanguagePackageRepo
Node.js / TypeScript@danipa/sdkDanipa/node-sdk
PHPdanipa/sdkDanipa/php-sdk
Pythondanipa(in the platform monorepo, mirrored at PyPI)
Javacom.danipa:danipa-java-sdkDanipa/java-sdk

All four SDKs are published from the same OpenAPI source — model shapes are guaranteed in sync with the API.

Common shape

Every SDK:

  • Accepts your API key at construction time.
  • Exposes a method per endpoint, with typed request and response.
  • Sends an Idempotency-Key automatically when you call a mutating method (you can override).
  • Surfaces errors as the standard envelope (status code + errors[].code).

Node.js

npm install @danipa/sdk
import { Danipa } from '@danipa/sdk';

const danipa = new Danipa({ apiKey: process.env.DANIPA_API_KEY });

const balance = await danipa.wallets.balance();
console.log(balance);

const transfer = await danipa.transfers.create({
  amount: '10.00',
  currency: 'USD',
  recipient: '+233500000000',
});
console.log(transfer.id);

The SDK is fully typed. Hover any method in your IDE for the shape of the request and response.

PHP

composer require danipa/sdk
use Danipa\Client;

$danipa = new Client(['api_key' => getenv('DANIPA_API_KEY')]);

$balance = $danipa->wallets->balance();
echo json_encode($balance);

$transfer = $danipa->transfers->create([
  'amount' => '10.00',
  'currency' => 'USD',
  'recipient' => '+233500000000',
]);
echo $transfer->id;

Python

pip install danipa
import os
from danipa import Danipa

danipa = Danipa(api_key=os.environ['DANIPA_API_KEY'])

balance = danipa.wallets.balance()
print(balance)

transfer = danipa.transfers.create(
    amount='10.00',
    currency='USD',
    recipient='+233500000000',
)
print(transfer.id)

Java

<dependency>
  <groupId>com.danipa</groupId>
  <artifactId>danipa-java-sdk</artifactId>
  <version>1.0.0</version>
</dependency>
import com.danipa.sdk.Danipa;
import com.danipa.sdk.transfers.CreateTransferRequest;

var danipa = Danipa.builder()
  .apiKey(System.getenv("DANIPA_API_KEY"))
  .build();

var balance = danipa.wallets().balance();
System.out.println(balance);

var transfer = danipa.transfers().create(
  CreateTransferRequest.builder()
    .amount("10.00")
    .currency("USD")
    .recipient("+233500000000")
    .build()
);
System.out.println(transfer.id());

Common operation patterns

The snippets below mirror the most common merchant flows across languages. They use the same package names introduced above.

Create a payment link

PaymentLink link = danipa.paymentLinks().create(
    CreatePaymentLinkRequest.builder()
        .title("Widget Purchase")
        .amount(new BigDecimal("50.00"))
        .currency("GHS")
        .amountFixed(true)
        .build()
);
System.out.println("Share: " + link.getUrl());
const link = await danipa.paymentLinks.create({
  title: 'Widget Purchase',
  amount: 50.00,
  currency: 'GHS',
  amountFixed: true,
});
console.log(`Share: ${link.url}`);
$link = $danipa->paymentLinks->create([
    'title' => 'Widget Purchase',
    'amount' => 50.00,
    'currency' => 'GHS',
    'amountFixed' => true,
]);
echo "Share: " . $link->url;
link = danipa.payment_links.create(
    title="Widget Purchase",
    amount=50.00,
    currency="GHS",
    amount_fixed=True,
)
print(f"Share: {link.url}")

Send an invoice

Invoice invoice = danipa.invoices().create(
    CreateInvoiceRequest.builder()
        .customerName("Jane Customer")
        .customerEmail("jane@customer.com")
        .lineItems(List.of(LineItem.of("Widget A", 2, new BigDecimal("10.00"))))
        .currency("GHS")
        .dueDate(LocalDate.of(2026, 4, 1))
        .build()
);
danipa.invoices().send(invoice.getId());
const invoice = await danipa.invoices.create({
  customerName: 'Jane Customer',
  customerEmail: 'jane@customer.com',
  lineItems: [{ description: 'Widget A', quantity: 2, unitPrice: 10.00 }],
  currency: 'GHS',
  dueDate: '2026-04-01',
});
await danipa.invoices.send(invoice.id);

Verify a webhook

All SDKs include a Webhook.verify() helper that checks HMAC-SHA256 signatures and enforces the 300-second replay window. See Webhooks for the full algorithm if you'd rather hand-roll it.

boolean valid = Webhook.verify(
    request.getHeader("X-Danipa-Signature"),
    request.getHeader("X-Danipa-Timestamp"),
    requestBody,
    webhookSecret
);
const event = Webhook.verify(req.rawBody, {
  signature: req.headers['x-danipa-signature'],
  timestamp: req.headers['x-danipa-timestamp'],
  secret: process.env.WEBHOOK_SECRET,
});
from danipa import Webhook

event = Webhook.verify(
    payload=request.body,
    signature=request.headers["X-Danipa-Signature"],
    timestamp=request.headers["X-Danipa-Timestamp"],
    secret=os.environ["WEBHOOK_SECRET"],
)

Sandbox vs production

Every SDK accepts a baseUrl override:

new Danipa({
  apiKey: process.env.DANIPA_API_KEY,
  baseUrl: 'https://api.sandbox.danipa.com',  // default in the sandbox SDK distribution
});

Default is sandbox — the environment available today. Production (https://api.danipa.com) is reserved for general availability and is not yet live; set the base URL explicitly for production builds once it opens. Don't switch at runtime based on heuristics — use a build-time / env-var-driven config.

Versioning

SDKs follow semver against the platform's API version:

  • Major bump — backward-incompatible API change (rare; we ship parallel versions when possible).
  • Minor bump — additive (new endpoints, new fields).
  • Patch bump — bug fixes, doc updates.

The SDK tracks the API version at the vN level (v1 today). A v2 release of the API would ship a parallel SDK major version; v1 would continue to work for a deprecation period (currently 18 months minimum).

What's not in the SDKs

  • Webhook signature verification — that's HMAC of a request body keyed by your secret; the SDKs include a helper, but the pattern is small enough to hand-roll. See Webhooks.
  • OAuth flows for sub-merchant onboarding — separate package surface; ship in the dedicated marketplace SDK if/when needed.
  • Real-time streaming — the platform doesn't expose a streaming API today; SDKs don't have a streaming surface.

Error handling

Every SDK throws a typed error for the standard error envelope, giving you access to both the HTTP status and the errors[].code.

try {
    danipa.paymentLinks().create(request);
} catch (DanipaValidationException e) {
    // 400: Invalid request parameters
    log.error("Validation error: {}", e.getErrors());
} catch (DanipaAuthException e) {
    // 401/403: Authentication or authorization error
    log.error("Auth error: {}", e.getMessage());
} catch (DanipaRateLimitException e) {
    // 429: Rate limit exceeded
    log.error("Retry after: {}s", e.getRetryAfterSeconds());
} catch (DanipaApiException e) {
    // 5xx: Server error
    log.error("API error: {} {}", e.getStatusCode(), e.getMessage());
}

Catch the error type and branch on code — never string-match on the human-readable message.

Common pitfalls

What's next

Community libraries

We welcome community-contributed libraries. If you've built a Danipa client library, contact us to get it listed here.

LanguageLibraryMaintainerStatus
GoComing soonPlanned
RubyComing soonPlanned