Skip to content

Quick Start

Get from zero to your first successful payment collection in under 10 minutes.

Base URL: https://api.heydollr.app


Before You Begin

You need a verified Dollr merchant account with API credentials. If you haven't done this yet:

  1. Register at merchant.heydollr.app
  2. Complete identity verification (1–72 hours)
  3. Go to Settings → Developer → API Keys and generate a Client ID and Client Secret

Step 1 — Get an Access Token

Exchange your credentials for a JWT Bearer token. Every API call requires this token in the Authorization header.

POST /v1/jwt/client/obtain/token
curl -X POST "https://api.heydollr.app/v1/jwt/client/obtain/token" \
  -H "Content-Type: application/json" \
  -d '{
    "client_id":     "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET"
  }'
import requests

BASE_URL = "https://api.heydollr.app"

res = requests.post(f"{BASE_URL}/v1/jwt/client/obtain/token", json={
    "client_id":     "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET",
})
token = res.json()["access_token"]
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
const BASE_URL = "https://api.heydollr.app";

const { access_token } = await fetch(`${BASE_URL}/v1/jwt/client/obtain/token`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    client_id:     "YOUR_CLIENT_ID",
    client_secret: "YOUR_CLIENT_SECRET",
  }),
}).then(r => r.json());

const headers = {
  Authorization:  `Bearer ${access_token}`,
  "Content-Type": "application/json",
};

Response:

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expires_in": 60
}

Tip

Tokens expire after expires_in minutes. Refresh proactively — request a new token when less than 5 minutes remain.


Step 2 — Create a Party

A Party is a contact record for the person you're collecting from.

POST /v1/parties/create
curl -X POST "https://api.heydollr.app/v1/parties/create" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "fullname":     "Amara Kamara",
    "phone":        "231771234567",
    "email":        "amara@example.com",
    "country_code": "LR"
  }'
party = requests.post(f"{BASE_URL}/v1/parties/create", headers=headers, json={
    "fullname":     "Amara Kamara",
    "phone":        "231771234567",
    "email":        "amara@example.com",
    "country_code": "LR",
}).json()

party_id = party["id"]
const party = await fetch(`${BASE_URL}/v1/parties/create`, {
  method: "POST", headers,
  body: JSON.stringify({
    fullname:     "Amara Kamara",
    phone:        "231771234567",
    email:        "amara@example.com",
    country_code: "LR",
  }),
}).then(r => r.json());

const partyId = party.id;

Response:

{
  "id": 42,
  "fullname": "Amara Kamara",
  "phone": "231771234567",
  "email": "amara@example.com",
  "country_code": "LR",
  "created_at": "2025-06-01T10:00:00Z",
  "updated_at": "2025-06-01T10:00:00Z"
}

Step 3 — Create a Counterparty

Link the Party to your merchant account with a relationship type.

POST /v1/counterparties/create
curl -X POST "https://api.heydollr.app/v1/counterparties/create" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"relationship_type": "CUSTOMER", "party_id": 42}'
cp = requests.post(f"{BASE_URL}/v1/counterparties/create", headers=headers, json={
    "relationship_type": "CUSTOMER",
    "party_id":          party_id,
}).json()

counterparty_id = cp["id"]
const cp = await fetch(`${BASE_URL}/v1/counterparties/create`, {
  method: "POST", headers,
  body: JSON.stringify({ relationship_type: "CUSTOMER", party_id: partyId }),
}).then(r => r.json());

const counterpartyId = cp.id;

Step 4 — Create and Publish an Invoice

Create the invoice, add a line item, then publish it.

POST /v1/invoices/create
# Create invoice
curl -X POST "https://api.heydollr.app/v1/invoices/create" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "counterparty_id": 15,
    "currency":        "USD",
    "note":            "Consulting services",
    "fee_bearer":      "PAYER",
    "as_payment_link": true
  }'

# Add a line item (replace 101 with your invoice id)
curl -X POST "https://api.heydollr.app/v1/invoices/101/items/add" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Strategy Session", "currency": "USD", "qty": 1, "amount": 250.00}'

# Publish (locks the invoice and activates it for payment)
curl -X PUT "https://api.heydollr.app/v1/invoices/publish/101" \
  -H "Authorization: Bearer $TOKEN"
# Create invoice
invoice = requests.post(f"{BASE_URL}/v1/invoices/create", headers=headers, json={
    "counterparty_id": counterparty_id,
    "currency":        "USD",
    "note":            "Consulting services",
    "fee_bearer":      "PAYER",
    "as_payment_link": True,
}).json()
invoice_id = invoice["id"]

# Add a line item
requests.post(f"{BASE_URL}/v1/invoices/{invoice_id}/items/add", headers=headers, json={
    "name":     "Strategy Session",
    "currency": "USD",
    "qty":      1,
    "amount":   250.00,
})

# Publish
invoice = requests.put(f"{BASE_URL}/v1/invoices/publish/{invoice_id}", headers=headers).json()
print("Status:", invoice["status"])  # ACTIVE
// Create invoice
const invoice = await fetch(`${BASE_URL}/v1/invoices/create`, {
  method: "POST", headers,
  body: JSON.stringify({
    counterparty_id: counterpartyId,
    currency:        "USD",
    note:            "Consulting services",
    fee_bearer:      "PAYER",
    as_payment_link: true,
  }),
}).then(r => r.json());
const invoiceId = invoice.id;

// Add a line item
await fetch(`${BASE_URL}/v1/invoices/${invoiceId}/items/add`, {
  method: "POST", headers,
  body: JSON.stringify({ name: "Strategy Session", currency: "USD", qty: 1, amount: 250.00 }),
});

// Publish
const published = await fetch(`${BASE_URL}/v1/invoices/publish/${invoiceId}`, {
  method: "PUT", headers,
}).then(r => r.json());
console.log("Status:", published.status); // ACTIVE

Step 5 — Collect Payment

Create a checkout session, register the customer's wallet, then execute.

Generate your reference_id before calling execute

Store the UUID before the network call. You'll need it to query status if the response is lost.

# Detect payment method from phone (optional but recommended)
curl "https://api.heydollr.app/v1/predictions/mmo-provider-info?phone=231771234567&operation_type=COLLECTION" \
  -H "Authorization: Bearer $TOKEN"

# Create checkout session
curl -X POST "https://api.heydollr.app/v1/sessions/checkout" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"source_id": 101, "source_type": "INVOICE"}'

# Register customer wallet (use method/provider from prediction)
curl -X POST "https://api.heydollr.app/v1/payment-accounts/create?operation_type=COLLECTION" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "account_name": "John Doe",
    "provider":     "MTN_MOMO_LBR",
    "method":       "MTN_MOMO_LBR",
    "party_id":     42,
    "country_code": "LR",
    "insensitive_account_number": "231771234567"
  }'

# Execute — store reference_id FIRST
REFERENCE_ID=$(python3 -c "import uuid; print(uuid.uuid4())")
curl -X POST "https://api.heydollr.app/v1/executions/collection" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"session_id\":         \"55\",
    \"payment_account_id\": \"18\",
    \"currency\":           \"USD\",
    \"reference_id\":       \"$REFERENCE_ID\"
  }"
import uuid

# Detect payment method from phone
mmo = requests.get(f"{BASE_URL}/v1/predictions/mmo-provider-info", headers=headers, params={
    "phone": "231771234567", "operation_type": "COLLECTION",
}).json()
payment_method = mmo["payment_method"]
provider       = mmo["gateway_provider"]

# Create checkout session
session = requests.post(f"{BASE_URL}/v1/sessions/checkout", headers=headers, json={
    "source_id":   invoice_id,
    "source_type": "INVOICE",
}).json()
session_id = session["id"]

# Register customer wallet
account = requests.post(
    f"{BASE_URL}/v1/payment-accounts/create",
    headers=headers,
    params={"operation_type": "COLLECTION"},
    json={
        "account_name":               "Amara MTN Wallet",
        "provider":                   provider,
        "method":                     payment_method,
        "party_id":                   party_id,
        "country_code":               "LR",
        "insensitive_account_number": "231771234567",
    },
).json()

# Execute — generate and store reference_id BEFORE the call
reference_id = str(uuid.uuid4())
execution = requests.post(f"{BASE_URL}/v1/executions/collection", headers=headers, json={
    "session_id":         str(session_id),
    "payment_account_id": str(account["id"]),
    "currency":           "USD",
    "reference_id":       reference_id,
}).json()
print("Execution status:", execution["status"])
import { randomUUID } from "crypto";

// Detect payment method from phone
const mmo = await fetch(
  `${BASE_URL}/v1/predictions/mmo-provider-info?phone=231771234567&operation_type=COLLECTION`,
  { headers }
).then(r => r.json());

// Create checkout session
const session = await fetch(`${BASE_URL}/v1/sessions/checkout`, {
  method: "POST", headers,
  body: JSON.stringify({ source_id: invoiceId, source_type: "INVOICE" }),
}).then(r => r.json());

// Register customer wallet
const account = await fetch(
  `${BASE_URL}/v1/payment-accounts/create?operation_type=COLLECTION`,
  {
    method: "POST", headers,
    body: JSON.stringify({
      account_name:               "Amara MTN Wallet",
      provider:                   mmo.gateway_provider,
      method:                     mmo.payment_method,
      party_id:                   partyId,
      country_code:               "LR",
      insensitive_account_number: "231771234567",
    }),
  }
).then(r => r.json());

// Execute — generate and store reference_id BEFORE the call
const referenceId = randomUUID();
const execution = await fetch(`${BASE_URL}/v1/executions/collection`, {
  method: "POST", headers,
  body: JSON.stringify({
    session_id:         String(session.id),
    payment_account_id: String(account.id),
    currency:           "USD",
    reference_id:       referenceId,
  }),
}).then(r => r.json());
console.log("Execution status:", execution.status);

Step 6 — Check Payment Status

GET /v1/status/collection/{reference_id}
curl "https://api.heydollr.app/v1/status/collection/$REFERENCE_ID" \
  -H "Authorization: Bearer $TOKEN"
status = requests.get(
    f"{BASE_URL}/v1/status/collection/{reference_id}",
    headers=headers,
).json()
print(status["status"])  # PENDING → PROCESSING → COMPLETED
const status = await fetch(`${BASE_URL}/v1/status/collection/${referenceId}`, { headers })
  .then(r => r.json());
console.log(status.status); // PENDING → PROCESSING → COMPLETED

Status progression: PENDINGPROCESSINGCOMPLETED (or FAILED)

Note

Mobile money payments may stay in PROCESSING for several minutes while the carrier confirms. Do not retry during this window — query status instead.


What's Next

Task Where to go
Full invoice and order management Invoices · Orders
Send payouts to mobile wallets Sessions · Executions
Preview fees before executing Predictions
Live status push (no polling) Realtime Keys
Error handling and retries Error Handling
Full step-by-step flows Integration Guide
Term definitions Glossary