Skip to main content

Partner API Reference

Vektrum Partner API

This document is the complete technical reference for Vektrum execution-rail partners. It covers authentication, all three partner API endpoints, webhook verification, error codes, and an integration checklist.

API version: 2026-04-25 — Base URL: https://vektrum.io

Authentication

All partner API endpoints require a partner API key passed as a Bearer token in the Authorization header:

Authorization: Bearer vkp_live_<your_64hex_key>

Keys are issued in two environments: vkp_live_ for production and vkp_test_ for sandbox. Each prefix is followed by 64 hex characters (73 characters total). Only the SHA-256 hash is stored in Vektrum's database — the plaintext key is shown once at issuance and cannot be recovered. If you lose your key, an admin must rotate it (the previous key is immediately invalidated).

To obtain your API key, contact operations@vektrum.io. An admin will issue credentials via the Vektrum admin dashboard at /dashboard/admin/partners. If outbound webhooks are enabled for your integration, Vektrum will also issue a partner-specific webhook signing secret.

Endpoints

GET/api/partner/releases/:id

Fetch the current state of a release. Use this to poll for pending releases if you did not receive the webhook, or to confirm the release is still in pending state before executing payment. Partners can only access releases for deals associated with their partner account.

Response 200:

All amount fields are USD dollars. Fee is charged to the funder on top of the milestone amount — the contractor always receives the full gross minus any retainage.

{
  "release": {
    "id": "uuid",
    "deal_id": "uuid",
    "deal_title": "string",
    "milestone_id": "uuid",
    "milestone_title": "string",
    "amount": 50000,
    "fee_amount": 500,
    "retainage_amount": 5000,
    "net_to_contractor": 45000,
    "execution_status": "pending | confirmed | failed",
    "execution_rail": "external_manual",
    "execution_notes": "string | null",
    "authorized_at": "ISO 8601"
  }
}
403

Deal not associated with your partner account

404

Release not found

POST/api/partner/releases/:id/confirm

Record that you have executed the authorized payment on your rail. Vektrum records the external execution and updates internal release, billing, and audit records, then transitions the release to confirmed status. This endpoint is idempotent — if the release is already confirmed, it returns 200 with alreadyConfirmed: true and takes no further action. Safe to retry on network error.

Request body:

{
  "payment_method": "wire | ach | check | other",
  "payment_reference": "string (wire ref, ACH trace, check number)",
  "executed_at": "ISO 8601 (optional, defaults to now)",
  "notes": "string (optional)",
  "proof_document_id": "uuid (optional)"
}

Response 200 (first confirmation):

{
  "success": true,
  "releaseId": "uuid",
  "execution_status": "confirmed",
  "execution_rail": "external_manual",
  "confirmed_by": "partner",
  "partner_id": "uuid",
  "external": {
    "payment_method": "wire",
    "payment_reference": "FED-20250415-00123",
    "executed_at": "2025-04-15T16:00:00.000Z",
    "notes": null,
    "proof_document_id": null
  },
  "billing": {
    "gross_amount": 50000,
    "fee_amount": 500,
    "retainage_amount": 5000,
    "net_to_contractor": 45000,
    "billing_rate_bps": 100,
    "total_debit": 50500,
    "committed": true
  },
  "ledger_updated": true,
  "warnings": []
}

Response 200 (already confirmed — idempotent):

{
  "success": true,
  "releaseId": "uuid",
  "alreadyConfirmed": true,
  "execution_status": "confirmed",
  "external_payment_reference": "FED-20250415-00123",
  "external_executed_at": "2025-04-15T16:00:00.000Z",
  "note": "This release has already been confirmed. No further action was taken."
}
409

State changed by a concurrent request

Idempotency: Already-confirmed releases return 200 with alreadyConfirmed: true. If you receive a network timeout, retry with the same body — the second call will detect the confirmed state and return safely.

POST/api/partner/releases/:id/fail

Record that execution failed on your rail. Vektrum cancels the balance reservation, transitions the release to failed status, and records the reason in the audit log. The pending authorization is marked failed and must be re-authorized before retry. The milestone remains in released state — contact Vektrum admin if the milestone itself needs to be reverted.

Request body:

{
  "reason": "string (min 10 chars)"
}

Response 200:

{
  "success": true,
  "releaseId": "uuid",
  "execution_status": "failed",
  "execution_rail": "external_manual",
  "reason": "Wire rejected by receiving bank — account number mismatch.",
  "reservation_cancelled": true,
  "milestone_status_unchanged": true,
  "note": "Release marked failed and funded-balance reservation freed. Milestone remains in released state — contact Vektrum admin to revert if needed."
}

Webhook Verification

Outbound webhooks are optional. If a webhook URL is configured for your integration, Vektrum will deliver a signed release.authorized event when the 10-condition gate passes on an external-rail deal. Partners without a configured webhook URL can poll GET /api/partner/releases/:id instead.

When Vektrum delivers a webhook to your endpoint, it includes an X-Vektrum-Signature header with this format:

X-Vektrum-Signature: t=<unix_timestamp>,sha256=<hmac_hex>

The HMAC-SHA256 is computed over <timestamp>.<raw_body> using your partner-specific signing secret. The signing secret is distinct per partner and rotatable on demand via the admin dashboard.

Timestamp tolerance: Enforce a 5-minute (300-second) tolerance window on the t value. Reject any webhook where |now() - t| > 300 seconds. This prevents replay attacks — a captured webhook payload cannot be replayed after 5 minutes.

Timing-safe comparison: Always use a constant-time comparison (e.g. crypto.timingSafeEqual in Node.js or hmac.compare_digest in Python) to prevent timing side-channel attacks.

TypeScript

import crypto from 'crypto'

function verifyVektrumSignature(
  rawBody: string,
  signatureHeader: string,
  secret: string,
  toleranceSeconds = 300
): boolean {
  const parts = Object.fromEntries(
    signatureHeader.split(',').map(p => p.split('='))
  )
  const ts = parts['t']
  const received = parts['sha256']
  if (!ts || !received) return false

  const age = Math.floor(Date.now() / 1000) - parseInt(ts, 10)
  if (Math.abs(age) > toleranceSeconds) return false

  const expected = crypto
    .createHmac('sha256', secret)
    .update(ts + '.' + rawBody)
    .digest('hex')

  return crypto.timingSafeEqual(
    Buffer.from(received),
    Buffer.from(expected)
  )
}

Python

import hmac, hashlib, time

def verify_vektrum_signature(
    raw_body: str,
    signature_header: str,
    secret: str,
    tolerance: int = 300
) -> bool:
    parts = dict(
        p.split("=", 1)
        for p in signature_header.split(",")
    )
    ts = parts.get("t")
    received = parts.get("sha256")
    if not ts or not received:
        return False
    if abs(time.time() - int(ts)) > tolerance:
        return False
    signed_payload = (ts + "." + raw_body).encode()
    expected = hmac.new(
        secret.encode(),
        signed_payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(received, expected)

Error Codes

StatusCodeMeaning in Vektrum context
200OKRequest succeeded. For confirm, check alreadyConfirmed field for idempotent re-submissions.
400Bad RequestMissing required field or invalid value. Check the errors array in the response body.
401UnauthorizedAPI key missing, malformed, or inactive. Verify your Authorization: Bearer header.
403ForbiddenYour partner account does not own the deal that contains this release.
404Not FoundRelease not found.
409ConflictA concurrent request changed the release state before yours completed. Fetch current state and retry if appropriate.
422UnprocessableThe release is not in the expected state for this operation (e.g. confirming an already-failed release).
429Too Many RequestsRate limit exceeded for your partner API key. Back off and retry.
500Internal ErrorVektrum server error. Retry with exponential backoff. If persistent, contact support.

Integration Checklist

Before going live with a real release, verify each of the following:

  • Received API key from Vektrum admin
  • Confirmed GET /api/partner/releases/:id returns expected shape
  • Tested confirm endpoint with a sandbox release
  • Tested fail endpoint with a sandbox release
  • Set up idempotency handling (retry on network error, check alreadyConfirmed)
  • Confirmed audit log entries appear in Vektrum dashboard after confirm/fail calls
  • If webhooks enabled: received partner signing secret from Vektrum admin
  • If webhooks enabled: verified HMAC signature on a test delivery
  • If webhooks enabled: enforced 5-minute timestamp tolerance on signature verification

Vektrum Partner API v1 · For approved integration partners · operations@vektrum.io