Guide

Raw API

Design your own experience. Register users, buy, sell and read balances server-to-server — no OroPocket UI.

The buy journey
Your serverOroPocket
  1. Your server:

    Register the user

    Trusted registration returns a persistent user_code. You own their UX and their OTP — we never message them.

    POST /partner/users/init
  2. Your server:

    Lock a quote

    Quote a rupee amount of gold or silver. The rate and the price block it was struck against are frozen.

    POST /partner/buy/quote

    Held for 10 minutes.

  3. Your server:

    Confirm it

    Send the quote_id with an Idempotency-Key. Your float is debited and the user is credited.

    POST /partner/buy/confirm

    A replay returns the original response rather than buying twice.

  4. OroPocket:

    It settles, or it refunds

    If fulfilment fails after the debit, the wallet is credited back and the order voided automatically.

  5. OroPocket:

    We call your webhook

    Signed, timestamped and retried across six hours. Selling mirrors the same quote-then-confirm shape.

Selling mirrors the same shape — quote, then confirm — except the proceeds settle into the end user's INR wallet rather than your float.

Register a user

Trusted registration returns a persistent user_code. You own the user's UX and OTP; we never message them.

POST/partner/users/init
curl -X POST https://api.oropocket.com/partner/users/init \
  -H "Authorization: Bearer oro_live_xxx" \
  -d '{"flow":"api","mobile":"9000000001","name":"Anya"}'

Buy

Two steps — quote, then confirm. Quotes lock a price for a short window.

POST/partner/buy/quote
FieldTypeDescription
user_codestringrequiredThe end user to buy for.
asset_typestringrequired"gold" or "silver".
amount_inrnumberrequiredAmount to spend in INR.
POST/partner/buy/confirm
# quote → returns quote_id + grams + rate
curl -X POST https://api.oropocket.com/partner/buy/quote \
  -H "Authorization: Bearer oro_live_xxx" \
  -d '{"user_code":"usr_xxx","asset_type":"gold","amount_inr":1000}'

# confirm
curl -X POST https://api.oropocket.com/partner/buy/confirm \
  -H "Authorization: Bearer oro_live_xxx" \
  -H "Idempotency-Key: <uuid>" \
  -d '{"quote_id":"tqt_xxx"}'
Buys debit your prepaid float (or postpaid credit line) and credit the end user. You collect the money from your user on your side.

Merchant markup (Pro)

On the Pro plan you set your own spread on our rates — added to buy, taken off sell. Your users are quoted the marked-up price, your wallet is debited the full marked-up amount on a buy, your user is credited the reduced amount on a sell, and the difference comes back to you on your monthly statement — Billing works the money through end to end. The same pair of percentages also prices the hosted checkout and anything you render from GET /partner/prices, so there is one number to keep straight, not three. Here is how to set it.

Markup is inert on live until we enable it on your account. Sandbox applies it the moment you save, so you can integrate and test end to end; live keeps quoting our rate until you ask us to switch it on. live_enabled tells you which side of that you are on.
GET/partner/dashboard/markup
PUT/partner/dashboard/markup

No capability needed — unlike every other endpoint on this page, the two markup calls are authorised by your token alone, so they work whatever your allowed_apis grants are.

Reading it returns your current setting and whether your plan allows one:

FieldTypeDescription
markup_buy_pctnumberYour buy spread, added to our rate. 0 means off, which is the default for every partner.
markup_sell_pctnumberYour sell spread, deducted from the proceeds. Independent of the buy side — one can be 0 and the other not.
max_pctnumberThe platform cap, currently 5, and it applies to each side separately. A stored value above it is clamped rather than honoured.
availablebooleanWhether your plan allows a markup. Free-tier tokens get false here rather than a 403 — so you can render it as a locked upsell instead of hiding it.
live_enabledbooleanWhether we have enabled markup on your live account. False means your live prices are unchanged no matter what you store here; sandbox ignores this.
appliedbooleanThe honest answer to “is this moving prices right now?” — true only when your plan allows it, the gate for this mode is open, and at least one percentage is above 0.
pending_approvalbooleanYou have set a spread but live is not enabled yet. Worth surfacing in your own admin UI so the number does not look broken.
sell_supportedbooleanFalse only on the older schema, where the sell field does not exist yet. Hide the sell control rather than writing to it.
tierstring"paid" or "free".

Setting it takes either field, or both. A field you omit is left alone, so you can change one side without reading the other first:

FieldTypeDescription
markup_buy_pctnumberoptional0 to max_pct (5), up to three decimal places. Send 0 to switch the buy side off.
markup_sell_pctnumberoptional0 to max_pct (5), same rules. Send 0 to switch the sell side off. Sending neither field is an error.
# read
curl https://api.oropocket.com/partner/dashboard/markup \
  -H "Authorization: Bearer oro_live_xxx"

# 2% on buys, 1% on sells
curl -X PUT https://api.oropocket.com/partner/dashboard/markup \
  -H "Authorization: Bearer oro_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"markup_buy_pct": 2, "markup_sell_pct": 1}'

# change only the sell side
curl -X PUT https://api.oropocket.com/partner/dashboard/markup \
  -H "Authorization: Bearer oro_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"markup_sell_pct": 0.5}'

Unlike the read, this one refuses rather than silently storing something else:

ErrorWhen
403 PRO_REQUIREDYou are on the free plan and tried to set a non-zero markup. Setting it to 0 is always allowed.
400 MARKUP_TOO_HIGHAbove max_pct. The message names the current cap.
400 INVALID_MARKUPNegative, or not a number.
The markup is not per-mode — sandbox and live share one value. Changing it while testing changes what your live users are quoted on their next buy.

What changes on a buy quote. Once a markup is in effect, POST /partner/buy/quote carries three extra fields. When it isn't — the default, and every free-tier partner — the response is exactly as documented above, with no extra fields at all, so an existing integration sees no change until you set one.

FieldTypeDescription
rate_inr_per_gramnumberWhat your user is charged — our rate plus your markup. Same field as always; on a marked-up quote it is the marked-up rate.
base_rate_inr_per_gramnumberOur rate before your markup. Present only when a markup applied.
markup_pctnumberThe percentage that was applied, after the 5% platform cap.
markup_amount_inrnumberRupee value of your markup on this order. Returned to you on your monthly statement.
Sandbox quotes apply the markup too, so you can verify the whole path — set it, quote, read the extra fields, confirm — on a test key before any of it touches a real user.

Sell

Sell mirrors buy — quote then confirm. Proceeds settle into the end user's INR wallet, not your float.

POST/partner/sell/quotesell
FieldTypeDescription
user_codestringrequiredWhose holdings to sell.
asset_typestringrequired"gold" or "silver".
quantity_gramsnumberoptionalExact grams to sell. Provide this OR amount_inr.
amount_inrnumberoptionalTarget NET rupees the user should receive — we work backwards to the grams. Provide this OR quantity_grams. If you have a sell markdown set, it comes out on top: we sell slightly more grams so your user still receives exactly this figure, and the spread is yours.

A sell markdown never comes out of amount_inr. Ask for ₹15,000 with a 2% markdown and your user is credited ₹15,000 — we sell about 2% more metal and hand you the difference. It is the mirror of the buy side, where a fixed rupee amount buys your user slightly less metal. quantity_grams quotes are unaffected: there the markdown reduces the payout, because the quantity is fixed.

FieldTypeDescription
quote_idstringPass to /sell/confirm.
quantity_gramsnumberGrams that will be sold.
rate_inr_per_gramnumberLocked sell rate.
net_amount_inrnumberWhat the user actually receives, after fees.
breakdownobjectgross_amount_inr, platform_fee_grams, platform_fee_inr, platform_fee_percentage (0.25), net_amount_inr, target_net_mode, proceeds_destination ('user_inr_wallet'), price_block_id.
expires_in_secondsnumberQuote TTL — 10 minutes.
POST/partner/sell/confirmsell
FieldTypeDescription
quote_idstringrequiredFrom /sell/quote.
Idempotency-KeyheaderoptionalRecommended — makes a retry safe.
Selling does not credit your partner wallet — the money goes to the user. A buy→sell round trip therefore still reduces your float. See Wallet.

Users, portfolio & balances

GET/partner/usersusers

Lists the users you registered. Add ?include=balances for a per-user holdings snapshot, and ?scope=all to also include embed-verified and attributed users (each row then carries a sources array). Paginate with limit (1–200) and offset.

GET/partner/users/:user_codeusers

One user's detail. Identity is deliberately masked — you address users only by user_code.

FieldTypeDescription
user_codestringYour handle for this user.
namestringAs supplied at registration.
mobile_maskedstringe.g. XXXXXX3210 — the full number is never returned.
email_maskedstringe.g. a***@example.com.
kyc_statusstringnot_started | under_review | approved | rejected.
user_existedbooleanTrue if the OroPocket account predated your registration (so they are not attributed to you).
registered_atstringWhen they were linked to you.
balancesobjectOnly with ?include=balances — your sub-wallet view of their holdings.
GET/partner/users/:user_code/portfoliobalance

Holdings for one user. Values are scoped to your sub-wallet, not the user's whole OroPocket balance — read sub-wallets before you reconcile against these numbers.

curl "https://api.oropocket.com/partner/users?include=balances" \
  -H "Authorization: Bearer oro_live_xxx"

curl "https://api.oropocket.com/partner/users/usr_xxx?include=balances" \
  -H "Authorization: Bearer oro_live_xxx"

Users must complete KYC before they can withdraw. Configure webhooks to get settlement events.

To try these from the dashboard rather than a terminal, see Make your first API call and Run a test buy.