Skip to content
StraventaDocs
API Reference

Payments Service API

Merchant onboarding, payment intents, refunds, settlements, disputes, webhooks, and public checkout

The Payments Service is the transaction core of 505pay. It handles the full merchant lifecycle — from KYB onboarding through live payment intents, refunds, disbursements, and webhook delivery. Every payment method (QRIS, VA, GoPay, OVO, etc.) runs through this service.

Base URLs

EnvironmentHostname
Sandboxhttps://sandbox.505pay.link
Productionhttps://api.505pay.link

Server-to-server merchant calls (intents, refunds, settings) authenticate with an API key (sk_test_… in sandbox, sk_live_… in production) created at Settings → API Keys in the dashboard. Admin / console flows authenticate with a Bearer JWT issued by the Auth Service. Public checkout endpoints (/v1/public/payments/intents/*) are unauthenticated — they are called by 505pay's hosted payment page, not your server.

Payment intent lifecycle

A payment intent is the authoritative record of a payment attempt. It moves through states as the payer interacts with the PSP.

Idempotency

Pass Idempotency-Key: <uuid> on POST /v1/payments/intents to guarantee at-most-once creation. Replaying the same key returns the original intent without double-charging.

First payment in 3 steps

# 1. Create a payment intent (QRIS Dynamic — change allowed_channels for other methods)
curl -X POST https://sandbox.505pay.link/v1/payments/intents \
  -H "Authorization: Bearer $PAYOPS_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-1234-v1" \
  -d '{
    "merchant_id": "'"$PAYOPS_MERCHANT_ID"'",
    "amount_idr": 50000,
    "max_uses": 1,
    "description": "Order #1234",
    "allowed_channels": ["qris"]
  }'

# 2. Show the payer the checkout — redirect to intent.checkout_url, or render intent.qr_string

# 3. Listen for the payment.completed webhook on your registered endpoint
const intent = await fetch('https://sandbox.505pay.link/v1/payments/intents', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.PAYOPS_SECRET_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': 'order-1234-v1',
  },
  body: JSON.stringify({
    merchant_id: process.env.PAYOPS_MERCHANT_ID,
    amount_idr: 50_000,
    max_uses: 1,
    description: 'Order #1234',
    allowed_channels: ['qris_dynamic'],
  }),
}).then((r) => r.json());

console.log(intent.checkout_url);  // hosted page; or render intent.qr_string yourself
import os, requests

intent = requests.post(
    'https://sandbox.505pay.link/v1/payments/intents',
    headers={
        'Authorization': f"Bearer {os.environ['PAYOPS_SECRET_KEY']}",
        'Idempotency-Key': 'order-1234-v1',
    },
    json={
        'merchant_id': os.environ['PAYOPS_MERCHANT_ID'],
        'amount_idr': 50_000,
        'max_uses': 1,
        'description': 'Order #1234',
        'allowed_channels': ['qris_dynamic'],
    },
).json()

print(intent['checkout_url'])
import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "os"

    "github.com/google/uuid"
)

body, _ := json.Marshal(map[string]any{
    "merchant_id":      os.Getenv("PAYOPS_MERCHANT_ID"),
    "amount_idr":       50_000,
    "max_uses":         1,
    "description":      "Order #1234",
    "allowed_channels": []string{"qris"},
    "metadata":         map[string]string{"order_id": "1234"},
})
req, _ := http.NewRequest("POST",
    "https://sandbox.505pay.link/v1/payments/intents",
    bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("PAYOPS_SECRET_KEY"))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", "order-1234-"+uuid.New().String())
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
// intent.checkout_url is in the JSON response
var intent map[string]any
_ = json.NewDecoder(resp.Body).Decode(&intent)
fmt.Println(intent["checkout_url"])
<?php
require 'vendor/autoload.php'; // Guzzle

$client = new \GuzzleHttp\Client();
$res = $client->post('https://sandbox.505pay.link/v1/payments/intents', [
    'headers' => [
        'Authorization'  => 'Bearer ' . getenv('PAYOPS_SECRET_KEY'),
        'Content-Type'   => 'application/json',
        'Idempotency-Key' => 'order-1234-' . \Ramsey\Uuid\Uuid::uuid4(),
    ],
    'json' => [
        'merchant_id'      => getenv('PAYOPS_MERCHANT_ID'),
        'amount_idr'       => 50000,
        'max_uses'         => 1,
        'description'      => 'Order #1234',
        'allowed_channels' => ['qris_dynamic'],
        'metadata'         => ['order_id' => '1234'],
    ],
]);
$intent = json_decode($res->getBody(), true);
echo $intent['checkout_url']; // hosted page; or render $intent['qr_string'] yourself

See the full Accept your first payment recipe for the webhook + fulfilment loop.


Endpoint reference

Merchant onboarding (KYB)

Create and submit merchants through KYB. Progress through draft → submitted → approved/rejected.

GET/v1/payments/agreements/current

Get current agreement template

GET/v1/payments/document-requirements

List KYB document requirements

GET/v1/payments/industries

List non-prohibited industries

GET/v1/payments/merchants/{id}

Get a merchant

GET/v1/payments/merchants/{id}/beneficial-owners

List beneficial owners

GET/v1/payments/merchants/{id}/documents

List documents

GET/v1/payments/merchants/me

List caller's merchants

POST/v1/payments/merchants

Create a merchant draft

POST/v1/payments/merchants/{id}/agreements

Record agreement acceptance

POST/v1/payments/merchants/{id}/beneficial-owners

Add a beneficial owner

POST/v1/payments/merchants/{id}/documents

Upload a KYB document

POST/v1/payments/merchants/{id}/submit

Submit merchant through KYB

PATCH/v1/payments/merchants/{id}

Partial-update a draft merchant

PATCH/v1/payments/merchants/{id}/beneficial-owners/{ownerId}

Update beneficial owner

DELETE/v1/payments/merchants/{id}/beneficial-owners/{ownerId}

Delete a beneficial owner

Team

Add and remove merchant team members.

Payment intents

Create, list, and cancel payment intents. Track attempt history.

Refunds

Issue full or partial refunds and list them.

Settlements

View settlement batches and payout settings.

Disbursements

Create, approve/reject disbursements with two-eyes workflow. Manage recipients and batch uploads.

GET/v1/payments/disbursements

List disbursements

GET/v1/payments/disbursements/{id}

Get a single disbursement

GET/v1/payments/disbursements/batches

List uploaded disbursement batches

GET/v1/payments/disbursements/batches/{id}

Get a disbursement batch (with row-level status)

GET/v1/payments/recipients

List disbursement recipients (address book)

GET/v1/payments/recipients/{id}

Get a disbursement recipient

GET/v1/payments/reports/disbursements

List disbursement batches (paginated)

GET/v1/payments/reports/disbursements/{id}

Get a disbursement batch

GET/v1/payments/reports/disbursements/{id}/items

Get line items for a disbursement batch

POST/v1/payments/disbursements

Create a new disbursement (status=pending under threshold, pending_approval over)

POST/v1/payments/disbursements/{id}/approve

Approve a pending_approval disbursement (two-eyes; AC-42.5)

POST/v1/payments/disbursements/{id}/reject

Reject a pending_approval disbursement (two-eyes; AC-42.5)

POST/v1/payments/disbursements/batches

Upload a CSV batch of disbursements (AC-42.6 — idempotent via csv_sha256)

POST/v1/payments/recipients

Create a disbursement recipient

POST/v1/payments/recipients/{id}/verify

Verify a recipient's bank account via PSP account validation

POST/v1/payments/webhooks/{provider}/disbursements

PSP disbursement webhook receiver — Flip and other providers (AC-42.8)

POST/v1/payments/webhooks/uob/disbursements

UOB advisory disbursement webhook (JWKS-kid signed notification)

PATCH/v1/payments/recipients/{id}

Update a disbursement recipient

DELETE/v1/payments/recipients/{id}

Deactivate a disbursement recipient

Payouts

Merchant payout accounts, schedules, and payout history.

GET/v1/payments/merchants/{merchant_id}/payout-accounts

List a merchant's payout accounts

GET/v1/payments/merchants/{merchant_id}/payout-schedule

Get a merchant's payout schedule

GET/v1/payments/merchants/{merchant_id}/payouts

List the merchant's historical payouts (paginated)

GET/v1/payments/merchants/{merchant_id}/payouts/{id}

Get a single payout (with line items)

GET/v1/payments/merchants/{merchant_id}/payouts/next

Get the projected next payout for the merchant

POST/v1/payments/admin/merchants/{merchant_id}/payout-accounts/{id}/reject

Reject a pending payout account (admin)

POST/v1/payments/admin/merchants/{merchant_id}/payout-accounts/{id}/revoke

Revoke a verified payout account (admin; opens a new pending row)

POST/v1/payments/admin/merchants/{merchant_id}/payout-accounts/{id}/verify

Mark a pending payout account as verified (admin)

POST/v1/payments/admin/merchants/{merchant_id}/payout-schedule/pause

Pause a merchant's payout schedule (admin)

POST/v1/payments/admin/merchants/{merchant_id}/payout-schedule/resume

Resume a merchant's payout schedule (admin)

POST/v1/payments/merchants/{merchant_id}/payout-accounts

Submit a payout bank account (lands as pending_verification)

PUT/v1/payments/merchants/{merchant_id}/payout-schedule

Update a merchant's payout schedule

Pricing & billing

Tenant-level pricing templates, per-merchant overrides, billing charges, and statements.

Reporting & transactions

Revenue KPIs, transaction ledger, drill-through detail, and async CSV export.

Disputes (chargebacks)

View, respond to, and accept chargeback disputes.

Payment channels & routing

Enable payment channels and manage routing rules.

PSP credentials

Manage Payment Service Provider credentials and rotation.

API keys

Manage API keys — create, update, revoke, and monitor for leaked keys.

Webhooks

Webhook subscriptions for event delivery.

Public checkout (unauthenticated)

Called by 505pay's hosted payment page — no Authorization header required.

PSP webhooks (inbound)

Inbound webhook endpoint called by PSP providers.

Health & metadata

Liveness and readiness probes.

Ungrouped operations

84 operations in the spec are not listed in the groups file. Add their operationIds to content/docs/api/payments.groups.json.

GET/v1/payments/admin/fee-schedules

List owner downstream fee schedules

GET/v1/payments/admin/owner-invoices

List owner per-period downstream-fee invoices

GET/v1/payments/admin/owner-invoices/{id}

Get an owner invoice with per-event attribution lines

GET/v1/payments/admin/owner-reserve

Get the owner payout reserve percentage

GET/v1/payments/admin/plan-subscriptions

List all tenants' Straventa subscriptions (platform admin)

GET/v1/payments/admin/plans

List Straventa plans

GET/v1/payments/admin/settlement-statements

List PSP settlement reconciliation statements

GET/v1/payments/admin/settlement-statements/{id}

Get a settlement statement with its reconciled lines

GET/v1/payments/admin/subscriptions

List subscriptions for a merchant

GET/v1/payments/admin/subscriptions/{id}

Get a single subscription

GET/v1/payments/cases

List unified payments cases (aggregates disputes + refunds)

GET/v1/payments/cases/{case_id}

Get a single case by composite id ({type}:{uuid})

GET/v1/payments/dashboard/channel-breakdown

Per-channel revenue breakdown for a date range

GET/v1/payments/dashboard/funnel

Conversion funnel (Created / Viewed / Charge submitted / Paid)

GET/v1/payments/dashboard/timeseries

Metric + grain timeseries

GET/v1/payments/dashboard/top-payment-links

Top payment links by paid amount for a date range

GET/v1/payments/disbursements/batches/{id}/export

Export an approved manual_file batch as a bank worksheet (CSV or XLSX)

GET/v1/payments/invoices

List merchant invoices (paginated)

GET/v1/payments/invoices/{id}

Get a single merchant invoice

GET/v1/payments/invoices/{id}/pdf

Download the rendered invoice PDF

GET/v1/payments/merchants/{id}/customers

List customers for a merchant

GET/v1/payments/merchants/{id}/customers/{cid}

Get customer profile with aggregates

GET/v1/payments/merchants/{id}/customers/{cid}/export

GDPR Article 15 export — full customer record as JSON

GET/v1/payments/merchants/{id}/customers/{cid}/gdpr-job

Get the active GDPR delete job for a customer (404 when none)

GET/v1/payments/merchants/{id}/customers/{cid}/intents

List payment intents for a customer

GET/v1/payments/merchants/{id}/customers/{cid}/notes

List notes for a customer (most-recent first)

GET/v1/payments/merchants/{id}/customers/{cid}/refunds

List refunds tied to a customer (most-recent first)

GET/v1/payments/merchants/{id}/verification

Get merchant KYC/KYB verification state

GET/v1/payments/onboarding/documents

List the caller's KYC documents (merchant-facing)

GET/v1/payments/onboarding/documents/{id}

Fetch metadata for a single KYC document

GET/v1/payments/platform/kyc-queue

List the platform KYC reviewer queue

GET/v1/payments/platform/kyc-verifications

List the platform KYC/KYB verification review queue

GET/v1/payments/refund-status/{shortcode}

Get public refund status (HMAC-authenticated, no JWT required)

GET/v1/payments/reports/disbursements/export

Stream the merchant's disbursement batches as a CSV file

GET/v1/payments/reports/settlements/export

Stream the merchant's settlements as a CSV file

GET/v1/payments/settings/email/{merchant_id}

Get merchant customer-email settings (reply_to + branding + verification state)

GET/v1/payments/settings/notifications/{merchant_id}

Read merchant notification preferences

GET/v1/payments/settings/webhooks/{id}/deliveries

List webhook delivery attempts for a subscription

GET/v1/payments/settings/webhooks/{id}/dlq

List dead-letter queue rows for a subscription

GET/v1/payments/settings/webhooks/events

List the canonical event catalogue

GET/v1/payments/settings/webhooks/retry-policy

Get the webhook dispatcher's retry policy

GET/v1/payments/subscriptions/current

Get the tenant's active Straventa subscription

GET/v1/public/payments/intents/{shortcode}/invoice.pdf

Download invoice PDF (public)

GET/v1/public/subscriptions/{token}

View subscription portal (anonymous)

POST/v1/customer-email-settings/verify-reply-to

Anonymous HMAC-token verification of merchant reply_to (mailbox round-trip)

POST/v1/payments/admin/fee-schedules

Create an owner downstream fee schedule

POST/v1/payments/admin/plans

Create or update a Straventa plan (platform admin)

POST/v1/payments/admin/settlement-statements

Ingest and reconcile a PSP settlement statement

POST/v1/payments/admin/subscriptions

Create a recurring subscription

POST/v1/payments/admin/subscriptions/{id}/cancel

Merchant-initiated cancel

POST/v1/payments/disbursements/batches/{id}/import-result

Upload the bank/portal result file to settle or fail disbursement rows

POST/v1/payments/disbursements/preview

Preview fee + total debit before submitting a disbursement (AC-42.9)

POST/v1/payments/intents/{id}/3ds-callback

Sandbox 3-D-Secure callback for the card_3ds channel

POST/v1/payments/invoices/{id}/resend

Re-send the invoice email

POST/v1/payments/invoices/{id}/void

Void an invoice

POST/v1/payments/merchants/{id}/customers/{cid}/delete

GDPR Article 17 — schedule customer erasure

POST/v1/payments/merchants/{id}/customers/{cid}/notes

Append a free-form note to a customer profile

POST/v1/payments/merchants/{id}/customers/import

Bulk-import customers from a CSV file

POST/v1/payments/onboarding/documents

Upload a KYC document (merchant-facing, multipart)

POST/v1/payments/onboarding/documents/{id}/replace

Re-upload (replace) a KYC document (multipart)

POST/v1/payments/platform/kyc-queue/{id}/approve

Approve a KYC document (terminal transition)

POST/v1/payments/platform/kyc-queue/{id}/reject

Reject a KYC document (terminal transition)

POST/v1/payments/platform/kyc-queue/{id}/start-review

Transition document from uploaded to under_review

POST/v1/payments/platform/kyc-verifications/{id}/disposition

Dispose a needs_review verification (verified or rejected)

POST/v1/payments/recon-questions

File a recon question / settlement-variance dispute

POST/v1/payments/settings/api-keys/{id}/rotate

Rotate an API key

POST/v1/payments/settings/email/{merchant_id}/send-verification

Send mailbox-round-trip verification email to the current reply_to

POST/v1/payments/settings/webhooks/{id}/deliveries/{deliveryId}/replay

Replay a single webhook delivery

POST/v1/payments/settings/webhooks/{id}/dlq/replay-all

Replay every dead-letter row for a subscription

POST/v1/payments/settings/webhooks/{id}/rotate

Rotate a webhook subscription's signing secret

POST/v1/payments/subscriptions

Subscribe the tenant to a Straventa plan

POST/v1/payments/subscriptions/{id}/cancel

Cancel the tenant's Straventa subscription

POST/v1/public/payments/telemetry/va-copy-click

Record a VA Copy-button click (anonymous telemetry)

POST/v1/public/subscriptions/{token}/cancel

Subscriber-initiated cancel

POST/v1/public/subscriptions/{token}/pause

Pause (active → paused)

POST/v1/public/subscriptions/{token}/resume

Resume (paused → active)

PUT/v1/payments/admin/fee-schedules/{id}

Update an owner downstream fee schedule

PUT/v1/payments/admin/owner-reserve

Set the owner payout reserve percentage

PUT/v1/payments/settings/email/{merchant_id}

Update merchant customer-email settings

PUT/v1/payments/settings/notifications/{merchant_id}

Update merchant notification preferences

PATCH/v1/payments/cases/{case_id}

Transition a case status (delegates to underlying dispute/refund)

PATCH/v1/payments/merchants/{id}/customers/{cid}/notes/{nid}

Update a customer note (replaces body; bumps updated_at)

PATCH/v1/public/subscriptions/{token}/email

Update subscriber email (rotates portal token)

DELETE/v1/payments/merchants/{id}/customers/{cid}/notes/{nid}

Hard-delete a customer note (irreversible)

Was this page helpful?

On this page