PIN Banking API

Banking-as-a-Service API Documentation

Getting Started

Welcome to the PIN Banking API. This RESTful API provides secure access to banking transactions and payment creation.

Base URL: https://sandboxau.banking.payitnow.io/api

Use the Postman Collection

Download the ready-made collection and import it directly into Postman: Baas AU API.postman_collection.json.

  1. Open Postman β†’ Import β†’ choose the JSON file.
  2. Create an environment that defines base_url (e.g. https://sandboxau.banking.payitnow.io), access_key (matches API_ACCESS_KEY), and optional token.
  3. Send the Authenticate request first; its test script automatically stores the JWT in the token variable.
  4. Subsequent requests reuse the JWT and compute the HMAC headers using those environment variables.

Payments are disabled in sandbox mode. Banking Circle blocks non-production settlement, so expect simulated β€œfailed” responses whenever BC_SANDBOX=true.

Authentication

The API uses JWT tokens for authentication. Tokens expire after 5 minutes and must be refreshed by obtaining a new token.

Get JWT Token

POST /api/v1/auth/token
{
    "username": "your_username",
    "access_key": "your_access_key"
}

PHP Example

<?php

// Step 1: Get JWT Token
function getAuthToken($username, $accessKey) {
    $ch = curl_init('https://sandboxau.banking.payitnow.io/api/v1/auth/token');

    $payload = json_encode([
        'username' => $username,
        'access_key' => $accessKey
    ]);

    curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Content-Type: application/json',
        'Accept: application/json'
    ]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($httpCode === 200) {
        $data = json_decode($response, true);
        return $data['token'];
    }

    throw new Exception('Authentication failed');
}

$token = getAuthToken('your_username', 'your_access_key');
echo "Token: " . $token . "\n";

Response: Returns a JWT token valid for 5 minutes. Store this token securely and use it in the Authorization header for all subsequent requests.

Account Balance Snapshot

Retrieve the latest account balance along with total credits, debits, and funds reserved for outgoing payments.

Endpoint

GET /api/v1/balance

Sample Response

{
    "date": "2025-01-15T03:15:40+00:00",
    "balance": {
        "available": "1250.00",
        "total_credits": "3000.00",
        "total_debits": "1500.00",
        "reserved_outgoing": "250.00"
    }
}

Field reference: available is credits minus debits minus reservations, total_credits/total_debits are raw ledger sums, and reserved_outgoing represents funds already earmarked for outgoing payments that have not failed or been cancelled yet (so they cannot be spent twice).

List Transactions

Retrieve a paginated list of all transactions including both deposits and withdrawals.

Endpoint

GET /api/v1/transactions

Query Parameters

Parameter Type Description
page integer Page number (default: 1)
per_page integer Items per page (default: 20, max: 100)
from_date date Start date (YYYY-MM-DD)
to_date date End date (YYYY-MM-DD)
type string Filter: deposit, withdrawal, all (default: all)

PHP Example with HMAC

<?php

function makeAuthenticatedRequest($method, $endpoint, $token, $accessKey, $data = []) {
    $timestamp = time();
    $body = $method === 'GET' ? '' : json_encode($data);

    // Generate HMAC signature
    $signature = hash_hmac('sha256', $body . $timestamp, $accessKey);

    $url = 'https://sandboxau.banking.payitnow.io' . $endpoint;

    if ($method === 'GET' && !empty($data)) {
        $url .= '?' . http_build_query($data);
    }

    $ch = curl_init($url);

    $headers = [
        'Authorization: Bearer ' . $token,
        'X-Signature: ' . $signature,
        'X-Timestamp: ' . $timestamp,
        'Content-Type: application/json',
        'Accept: application/json'
    ];

    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    if ($method === 'POST') {
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
    }

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    return [
        'code' => $httpCode,
        'body' => json_decode($response, true)
    ];
}

// Get transactions
$result = makeAuthenticatedRequest(
    'GET',
    '/api/v1/transactions',
    $token,
    'your_access_key',
    [
        'page' => 1,
        'per_page' => 20,
        'from_date' => '2025-01-01',
        'type' => 'all'
    ]
);

print_r($result['body']);

Example Response

{
    "data": [
        {
            "id": "txn_123",
            "date": "2025-01-15T10:30:00+00:00",
            "type": "deposit",
            "direction": "credit",
            "amount": "1500.00",
            "currency": "AUD",
            "counterparty": "ABC Corporation",
            "reference": "INV-2025-001",
            "status": "completed"
        },
        {
            "id": "pmt_456",
            "date": "2025-01-14T14:20:00+00:00",
            "type": "withdrawal",
            "direction": "debit",
            "amount": "500.00",
            "currency": "AUD",
            "counterparty": "Supplier XYZ",
            "reference": "Payment for services",
            "status": "completed"
        }
    ],
    "meta": {
        "current_page": 1,
        "per_page": 20,
        "total": 2,
        "last_page": 1,
        "from": 1,
        "to": 2
    }
}

Create Payment

Create a new outgoing payment. The API will validate sufficient balance before processing.

Sandbox calls return demo data only: the JSON matches production, but you will also see meta.sandbox_demo = true to indicate that no funds were moved.

Endpoint

POST /api/v1/payments

Request Body

Field Type Required Description
amount number Yes Payment amount (minimum: 0.01)
account string Yes Account number
name string Yes Beneficiary name
bsb string No Australian BSB (6 digits)
country string Yes 2-letter country code (e.g., AU)
reference string No Payment reference

PHP Example

<?php

$paymentData = [
    'amount' => 150.50,
    'account' => '12345678',
    'name' => 'John Doe',
    'bsb' => '123456',
    'country' => 'AU',
    'reference' => 'Invoice #INV-2025-001',
    'remittance_line1' => 'Payment for consulting services'
];

$result = makeAuthenticatedRequest(
    'POST',
    '/api/v1/payments',
    $token,
    'your_access_key',
    $paymentData
);

if ($result['code'] === 201) {
    echo "Payment created successfully!\n";
    echo "Payment ID: " . $result['body']['data']['id'] . "\n";
    echo "Status: " . $result['body']['data']['status'] . "\n";
} else {
    echo "Error: " . $result['body']['message'] . "\n";
}

Response: Returns 201 status code with payment details including payment ID and status.

Check Payment Status

Retrieve the current status of a payment. The API automatically checks with Banking Circle for the latest status.

Endpoint

GET /api/v1/payments/{id}

PHP Example

<?php

$paymentId = 123; // Your payment ID

$result = makeAuthenticatedRequest(
    'GET',
    '/api/v1/payments/' . $paymentId,
    $token,
    'your_access_key'
);

if ($result['code'] === 200) {
    $payment = $result['body']['data'];
    echo "Payment Status: " . $payment['status'] . "\n";
    echo "BC Status: " . ($payment['bc_status'] ?? 'N/A') . "\n";
    echo "Amount: " . $payment['amount'] . " " . $payment['currency'] . "\n";
} else {
    echo "Error: " . $result['body']['message'] . "\n";
}

Security

HMAC Signature Verification

All authenticated requests must include an HMAC signature to prevent tampering and replay attacks.

Required Headers

  • Authorization: Bearer {jwt_token}
  • X-Signature: {hmac_signature}
  • X-Timestamp: {unix_timestamp}

Signature Calculation

signature = HMAC-SHA256(request_body + timestamp, access_key)

Important: The timestamp must be within 30 seconds of the server time. Ensure your system clock is synchronized using NTP.

Rate Limiting

The API enforces rate limiting of 60 requests per minute per API key. Exceeding this limit will result in 429 (Too Many Requests) responses.

Best Practices

  • Never expose your access key in client-side code or public repositories
  • Store credentials securely using environment variables
  • Implement token refresh logic before the 5-minute expiry
  • Use HTTPS for all API requests
  • Log and monitor API errors and failed authentication attempts

Error Codes

The API uses standard HTTP response codes to indicate success or failure.

Code Status Description
200 OK Request successful
201 Created Resource created successfully
400 Bad Request Invalid request parameters
401 Unauthorized Invalid credentials, expired token, or invalid signature
404 Not Found Resource not found
422 Unprocessable Entity Validation error
429 Too Many Requests Rate limit exceeded
500 Internal Server Error Server error occurred

Error Response Format

{
    "error": "Error Type",
    "message": "Detailed error message describing what went wrong"
}