Y YoungPG Media
‹ All docs

API documentation

Last updated May 22, 2026

Getting started with the YoungPG API

The YoungPG reseller API lets you browse our catalog and buy accounts programmatically. All endpoints are JSON, prefixed with /api/v1/, and gated by an API key.

1. Mint a key

Open your API dashboard and click + New key. Give it a label so you can tell it apart from other keys later, then pick the scopes you need. The plaintext key is shown once — copy it immediately.

2. Make your first call

curl https://youngpgmedia.com.ng/api/v1/user/balance \
  -H "X-API-Key: ypg_..."

You should get back:

{
  "success": true,
  "data": { "balance_ngn": "0.00" }
}

3. Browse the catalog

curl "https://youngpgmedia.com.ng/api/v1/listings?per_page=5" \
  -H "X-API-Key: ypg_..."

Each listing includes a price_ngn (already in naira at our current rate) and an available_stock count.

4. Make a purchase

POST /api/v1/purchase debits your wallet in naira and returns the credentials immediately:

curl -X POST https://youngpgmedia.com.ng/api/v1/purchase \
  -H "X-API-Key: ypg_..." \
  -H "Content-Type: application/json" \
  -d '{"slug":"facebook-aged","quantity":2}'

That's the whole loop. Read the endpoint reference for the full surface, or the errors page for status codes and rate limits.

Authentication

Every call to /api/v1/* must include your API key in the X-API-Key header. Keys are minted from your dashboard and look like ypg_<48 hex chars>.

Showing the plaintext only once

When you create a key, the full plaintext is shown once. We store only the SHA-256 hash plus a 12-character prefix so you can identify the key in your dashboard later. If you lose the plaintext, revoke the key and mint a new one — there is no "view again".

Scopes

Each key carries a set of scopes that limit what it can do:

  • listings:read — browse categories and listings
  • orders:read — list your past orders
  • orders:write — call POST /api/v1/purchase
  • profile:read — read your YPG profile
  • profile:write — update your YPG profile
  • wallet:read — read your NGN balance

A 403 with Scope required: <scope> means the key you used doesn't have the scope the endpoint needs.

Expiration

Keys can carry an optional expires_at. After that timestamp, calls return 401. You can mint a fresh key at any time.

Revoking a key

Use the Revoke button on a key row in your dashboard. Revocation is immediate.

Endpoint reference

All requests must include X-API-Key: ypg_.... All responses share the shape { "success": bool, "message": string?, "data": ..., "meta"?: ... }. Money values are NGN.

User

  • GET /api/v1/user/profile — your YPG profile.
  • PUT /api/v1/user/profile — body { first_name?, last_name?, phone?, country? }.
  • GET /api/v1/user/balance{ balance_ngn }.

Catalog

  • GET /api/v1/categories — every active category.
  • GET /api/v1/categories/{id}/subcategories — drill-down.
  • GET /api/v1/listings — query params: category_id, subcategory_id, search, sort (one of sort_key, total_price, available_stock, title), direction (asc/desc), per_page (≤ 100), page.
  • GET /api/v1/listings/{slug} — single listing detail.

Orders

  • POST /api/v1/purchase — body { slug, quantity, promo_code? }. Returns { order_id, accounts: ["email:password", ...], amount_ngn, new_balance_ngn }. Rate-limited at 10/min separately from the global 60/min.
  • GET /api/v1/orders — paginated list of your orders.
  • GET /api/v1/orders/{id} — single order including delivered credentials.

Promo

  • POST /api/v1/promo/validate — body { code, slug, quantity } → returns the NGN discount and final amount without placing the order.

Errors & rate limits

Errors share the same envelope as successes, with success: false:

{
  "success": false,
  "message": "Insufficient wallet balance",
  "errors": null
}

Status codes

| Code | Meaning | |------|---------| | 200 | OK | | 201 | Resource created | | 400 | Business rule failed (e.g. insufficient balance, out of stock) | | 401 | Missing or invalid API key | | 403 | Scope missing, or account suspended | | 404 | Resource not found | | 422 | Body validation failed — errors contains per-field messages | | 429 | Rate limit exceeded — see Retry-After header | | 502 | Account delivery temporarily unavailable — retry shortly |

Rate limits

  • Global per key: 60 requests per minute across all endpoints.
  • Purchase endpoint: 10 requests per minute, on top of the global cap.

When you hit a limit you get a 429 with a Retry-After: <seconds> header. Back off for that many seconds before retrying — anything sooner just refreshes the cap.

Idempotency on purchase

POST /api/v1/purchase is not retry-safe. If a request times out or returns 502, do not simply retry — first call GET /api/v1/orders to see if the order actually landed. Double-retries can mean double-charges.