← Back to HomeDownload Postman collection
On this page
  • Table of contents
  • 1. Overview
  • What it is
  • The money model
  • 2. Quick start
  • Step 1. Check your key (ping)
  • Step 2. List available tasks
  • Step 3. Claim a slot for one worker
  • Step 4. The worker opens the link
  • Step 5. Submit proof
  • Step 6. Check the result
  • 3. Core concepts
  • Tasks and shared slots
  • Claims and the time window
  • The tracked link
  • Worker IDs
  • Rewards, kobo and naira
  • The submission lifecycle
  • Reversals
  • 4. Authentication and security
  • Bearer key
  • Getting your API key
  • Keeping the key safe
  • Rate limits and IP addresses
  • 5. Endpoint reference
  • 5.1 Ping
  • 5.2 List tasks
  • 5.3 Claim a task
  • 5.4 Claim status
  • 5.5 Submit proof
  • 5.6 Submission status
  • 5.7 Balance
  • 5.8 List submissions
  • 6. Error reference
  • 7. Rate limits and retries
  • Limits and headers
  • Backoff
  • What is safe to retry
  • Sample retry code: JavaScript
  • Sample retry code: PHP
  • 8. Best practices and integration checklist
  • Polling for status
  • Showing workers their status
  • Handling rejection reasons
  • Handling expired claims
  • Paying your workers
  • Going-live checklist
  • 9. Wallet, reversals and settlement
  • Reading the balance
  • Ledger entry types
  • Reversals and negative balances
  • Settlement
  • 10. Data handling and privacy
  • 11. FAQ and troubleshooting
  • 12. Versioning, changelog and support
  • Versioning
  • Changelog
  • Postman
  • Support

PawaBoost Partner Earn API

Version 1 · Base path /api/v1/earn · JSON over HTTPS

This guide is written for a developer who is integrating the Partner Earn API for the first time. It covers the concepts, a working quick start, every endpoint, every error, and the money model.

Table of contents

  1. Overview
  2. Quick start
  3. Core concepts
  4. Authentication and security (includes getting your API key)
  5. Endpoint reference
  6. Error reference
  7. Rate limits and retries
  8. Best practices and integration checklist
  9. Wallet, reversals and settlement
  10. Data handling and privacy
  11. FAQ and troubleshooting
  12. Versioning, changelog and support

1. Overview

What it is

The Partner Earn API lets a partner (your app, site or community) offer PawaBoost micro-tasks to your own users. A task is a small social action, such as following an account, liking a post or watching a video. Your user does the task, hands in a screenshot or other proof, and PawaBoost reviews it. For every approved task, PawaBoost credits your partner wallet.

It is for businesses that already have an audience and want to monetise it without building their own task marketplace.

The money model

Read this section before you write any code.

  • Workers are anonymous. A "worker" is just an ID you choose (externalUserId). PawaBoost never learns who the person is and never pays them.
  • PawaBoost credits the partner, not the worker. Each approved submission adds the task reward to your partner wallet.
  • You pay your own workers. How much of the reward you pass on, and how, is entirely between you and your users.
  • PawaBoost settles with you separately. Periodically, PawaBoost pays out your wallet balance to you. Each payout appears in your ledger as a SETTLEMENT entry with a payment reference.
  • Mistakes are reversible. If an approved submission is later found to be invalid, it is reversed and the amount is taken back from your wallet. See section 9.
text
 Your worker ──does task──▶ PawaBoost reviews ──approves──▶ PawaBoost credits YOUR wallet
                                                                      │
                          you pay your worker (your own rules)        │
                                                                      ▼
                                              PawaBoost settles your wallet to you

2. Quick start

Six steps, from "does my key work" to "has my worker been paid".

Set two variables first. BASE is the PawaBoost address, and KEY is your API key (create one first: see Getting your API key).

Linux / macOS

Linux / macOS
export BASE="https://www.pawaboost.com"
export KEY="pbp_live_xxxxxxxxxxxxxxxx"

Windows CMD

Windows CMD
set BASE=https://www.pawaboost.com
set KEY=pbp_live_xxxxxxxxxxxxxxxx

Step 1. Check your key (ping)

Linux / macOS
curl -s "$BASE/api/v1/earn/ping" -H "Authorization: Bearer $KEY"
Windows CMD
curl -s "%BASE%/api/v1/earn/ping" -H "Authorization: Bearer %KEY%"
JSON
{
  "success": true,
  "partnerId": "clpartner0001",
  "name": "Acme Rewards",
  "status": "ACTIVE"
}

Step 2. List available tasks

Linux / macOS
curl -s "$BASE/api/v1/earn/tasks?limit=2" -H "Authorization: Bearer $KEY"
Windows CMD
curl -s "%BASE%/api/v1/earn/tasks?limit=2" -H "Authorization: Bearer %KEY%"
JSON
{
  "success": true,
  "tasks": [
    {
      "id": "cltask000001",
      "title": "Follow @example on Instagram",
      "platform": "INSTAGRAM",
      "category": "FOLLOWERS",
      "type": "Instagram Follow",
      "rewardKobo": 3900,
      "remainingSlots": 12,
      "durationSeconds": null,
      "instructions": "Open the task link and follow the account using your real account. You must open the link we give you after claiming before you can submit proof."
    }
  ],
  "nextCursor": null
}

Step 3. Claim a slot for one worker

Linux / macOS
curl -s -X POST "$BASE/api/v1/earn/tasks/cltask000001/claim" \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{"externalUserId":"w_9f3a1c2e"}'
Windows CMD
curl -s -X POST "%BASE%/api/v1/earn/tasks/cltask000001/claim" -H "Authorization: Bearer %KEY%" -H "Content-Type: application/json" -d "{\"externalUserId\":\"w_9f3a1c2e\"}"
JSON
{
  "success": true,
  "claimId": "clclaim000001",
  "expiresAt": "2026-10-07T14:30:00.000Z",
  "redirectUrl": "https://www.pawaboost.com/r/AbCdEfGh1234"
}

Step 4. The worker opens the link

Show redirectUrl to the worker and have their own browser open it. They are sent on to the task (for example the Instagram profile) and PawaBoost records that the link was opened. They then do the action. You cannot do this step with curl on their behalf: the link must be opened by the worker. See the tracked link.

Step 5. Submit proof

Linux / macOS
curl -s -X POST "$BASE/api/v1/earn/claims/clclaim000001/submit" \
  -H "Authorization: Bearer $KEY" \
  -F "screenshot=@proof.png" \
  -F "proofUsername=worker_handle"
Windows CMD
curl -s -X POST "%BASE%/api/v1/earn/claims/clclaim000001/submit" -H "Authorization: Bearer %KEY%" -F "screenshot=@C:\proofs\proof.png" -F "proofUsername=worker_handle"
JSON
{
  "success": true,
  "submissionId": "clsub0000001",
  "status": "PENDING"
}

Step 6. Check the result

Linux / macOS
curl -s "$BASE/api/v1/earn/submissions/clsub0000001" -H "Authorization: Bearer $KEY"
Windows CMD
curl -s "%BASE%/api/v1/earn/submissions/clsub0000001" -H "Authorization: Bearer %KEY%"
JSON
{
  "success": true,
  "submissionId": "clsub0000001",
  "claimId": "clclaim000001",
  "taskId": "cltask000001",
  "externalUserId": "w_9f3a1c2e",
  "status": "APPROVED",
  "rewardKobo": "3900",
  "submittedAt": "2026-10-07T14:05:11.000Z",
  "reviewedAt": "2026-10-07T15:20:42.000Z",
  "reversed": false
}

When status is APPROVED, the reward has been credited to your wallet. Check it with GET /api/v1/earn/balance (see section 5.7).


3. Core concepts

Tasks and shared slots

A task is one action PawaBoost needs done a set number of times. Each unit of work is a slot. Slots are shared between all partners and PawaBoost's own users, so remainingSlots goes down as anyone claims. The task list can lag by about 30 seconds; the claim call is the authority.

To keep things fair, one partner cannot reserve every slot of a task. If you hit a limit, claiming returns 409 Claim limit reached for this task. Try another task, or wait for your open claims to finish or expire.

Claims and the time window

A claim reserves one slot for one worker. It is valid for 30 minutes (expiresAt). For tasks that need watching time, the window is the watch time plus 5 minutes, if that is longer than 30 minutes. If the worker does not submit in time, the claim becomes EXPIRED and the slot is released for others.

A worker can hold one active claim per task. After an expiry or a rejection the worker may claim the task again. After an approval they cannot.

The tracked link

Every claim comes with a one-time redirectUrl. When the worker opens it, PawaBoost records the time and redirects them to the task.

  • The link must be opened by the worker's own browser or app. Proof submitted before the link was opened is refused with 409 Open the task link before submitting proof.
  • For tasks that need watching time, the waiting time starts when the link is first opened.
  • The link is shown once, in the claim response. It is not returned by any other call. Hand it to the worker straight away.
  • The link stops working when the claim expires or is submitted.

Worker IDs

externalUserId identifies your worker. We treat it as an opaque string.

  • 1 to 128 characters, no leading or trailing spaces, no control characters.
  • Keep it stable: always use the same ID for the same person. Review history and worker standing follow the ID.
  • Do not send real names, emails or phone numbers. We recommend sending a one-way hash of your own user id, so the value means nothing to us:
JavaScript
// Node.js: derive a stable, anonymous worker id from your own user id.
import { createHmac } from "node:crypto";

export function workerId(userId, secret) {
  // `secret` is a long random string only your server knows.
  return "w_" + createHmac("sha256", secret).update(String(userId)).digest("hex").slice(0, 32);
}

Rewards, kobo and naira

Amounts are integer kobo. 100 kobo = 1 naira (₦1).

rewardKobo already includes any bonus agreed for your partner account. It is fixed when the worker submits, so later changes never alter an existing submission.

Worked example: a task shows rewardKobo: 3900.

  • 3900 kobo ÷ 100 = ₦39.00 per approved submission.
  • 25 approved submissions = 25 × 3900 = 97,500 kobo = ₦975.00 credited to your wallet.

Task lists show rewardKobo as a JSON number. Submissions and balances show money as a decimal string ("3900"), because totals can exceed the range a JSON number holds exactly. Parse them as big integers, never as floating point.

The submission lifecycle

A claim and its submission move through these states:

text
              claim                submit               review
  (none) ───────────────▶ OPEN ───────────────▶ SUBMITTED ─────────┬──▶ APPROVED
                           │                                       │
                           │ not submitted in time                 └──▶ REJECTED
                           ├────────────────────▶ EXPIRED
                           │ closed by PawaBoost
                           └────────────────────▶ CANCELLED
Claim statusMeaning
OPENThe worker may still submit before expiresAt.
SUBMITTEDProof received, waiting for review.
APPROVEDApproved. The reward was credited to your wallet.
REJECTEDRejected. The worker may claim the task again if slots remain.
EXPIREDNot submitted in time. The slot was released.
CANCELLEDClosed by PawaBoost. The slot was released.

The submission itself has three statuses: PENDING, APPROVED and REJECTED. A submission that is not reviewed within a few days is closed as REJECTED with a reason saying it was not reviewed in time. The worker may claim the task again.

Reversals

A reversal takes back an earlier approval that turned out to be invalid. The submission stays APPROVED with reversed: true, a REVERSAL entry appears in your ledger, and the amount is subtracted from your balance. The worker cannot claim that task again. Details are in section 9.


4. Authentication and security

Bearer key

Send your API key in the Authorization header on every request:

text
Authorization: Bearer pbp_live_<random characters>
  • Keys start with pbp_live_ followed by a long random string.
  • Your partner identity comes from the key alone. There is no partner id parameter. Anything you send that looks like one is ignored.
  • A missing, malformed, unknown or revoked key, and a suspended partner account, all return the same 401 Unauthorized. The response never says which.

Getting your API key

You create and manage your own keys in the PawaBoost app. There is no waiting for a key to be issued.

  1. Sign in to PawaBoost at https://www.pawaboost.com. If you do not have an account yet, sign up and verify your email address first.
  2. Ask support to link your account to your partner. Message PawaBoost support on Telegram or email (see Support) with your partner name and the email address of your PawaBoost account. A PawaBoost administrator links your account to your partner. Until then you will not see the Partner API page. One account belongs to one partner.
  3. Open Partner API. Go to your Profile and choose Partner API.
  4. Create a key. Choose New API Key, give it a name you will recognise (for example "Production server"), and confirm.
  5. Copy it now. The full key is shown once. PawaBoost keeps only a one-way fingerprint and cannot show it again. Copy it straight into your server's secret store.
  6. Test it with GET /api/v1/earn/ping (see the Quick start).

Limits and behaviour:

  • You can have at most 3 active keys at a time. Revoke one to create another.
  • You can create at most 5 keys per hour. Wait and try again if you hit the limit.
  • The page shows each key's name, the start of the key, when it was last used and its status. It never shows a full key again.
  • If your partner account is suspended (or not yet active), the page is read-only: you can see your keys but cannot create or revoke any, and your keys do not work until the account is active again. Contact support.
  • Anyone you want to manage keys needs their own PawaBoost account linked to your partner by support.

Keeping the key safe

  • Server-side only. Call the API from your backend. Never put the key in a web page, a mobile app, a browser script or a public repository. Anyone holding the key can claim tasks and read your balance as you.
  • Shown once. A key is displayed in full only once, when you create it. We store only a one-way fingerprint, so we cannot show it again. Save it in your secrets manager straight away. If you lose it, revoke it and create a new one.
  • Rotation. Rotate keys on a schedule and whenever someone with access leaves. Create the new key first on the Partner API page, deploy it, confirm it works with GET /ping, and only then revoke the old one. Up to 3 keys can be active at the same time, so rotation needs no downtime.
  • Revocation. If a key may have leaked, revoke it on the Partner API page straight away; it stops working immediately and returns 401 from then on. Then create a replacement. If you cannot sign in, contact support and we will revoke it for you.
  • HTTPS only. Use https:// for every call. Never send the key over plain HTTP.
  • Logging. Do not log the Authorization header or the key.

Rate limits and IP addresses

Each key is limited to a number of requests per minute (see section 7). Repeated failed authentication attempts from one IP address are temporarily blocked with 429, so do not retry a 401 in a loop. If you call from several servers, each server can use the same key; limits are counted per key, not per IP address.


5. Endpoint reference

All endpoints require Authorization: Bearer <key>. All responses are JSON and include Cache-Control: no-store and the rate-limit headers from section 7. Every success response contains "success": true; every error is { "success": false, "error": "<message>" }. Timestamps are ISO 8601 in UTC. Do not cache responses.

Method and pathPurpose
GET /api/v1/earn/pingCheck your key
GET /api/v1/earn/tasksList tasks with slots left
POST /api/v1/earn/tasks/{id}/claimClaim a slot for a worker
GET /api/v1/earn/claims/{id}Claim status
POST /api/v1/earn/claims/{id}/submitSubmit proof
GET /api/v1/earn/submissions/{id}One submission
GET /api/v1/earn/submissionsList your submissions
GET /api/v1/earn/balanceWallet totals and recent ledger

5.1 Ping

text
GET /api/v1/earn/ping

No parameters. Confirms the key works and which partner it belongs to.

JSON
{
  "success": true,
  "partnerId": "clpartner0001",
  "name": "Acme Rewards",
  "status": "ACTIVE"
}

Errors: 401, 429.

5.2 List tasks

text
GET /api/v1/earn/tasks
Query parameterTypeRules
limitintegerOptional. 1 to 50. Default 20.
cursorstringOptional. The nextCursor from the previous page.
Linux / macOS
curl -s "$BASE/api/v1/earn/tasks?limit=20" -H "Authorization: Bearer $KEY"
JSON
{
  "success": true,
  "tasks": [
    {
      "id": "cltask000001",
      "title": "Watch our video for 30 seconds",
      "platform": "YOUTUBE",
      "category": "WATCHTIME",
      "type": "YouTube Watch Time",
      "rewardKobo": 2500,
      "remainingSlots": 40,
      "durationSeconds": 30,
      "instructions": "Open the task link and watch the video for the full required time. You must open the link we give you after claiming before you can submit proof."
    }
  ],
  "nextCursor": "cltask000001"
}
FieldNotes
idUse this in the claim call.
rewardKoboInteger kobo you earn per approved submission.
remainingSlotsSlots left, up to about 30 seconds out of date.
durationSecondsWatch time the worker must wait, or null.
instructionsGeneric instructions you can show the worker.

Only tasks with slots left are listed, in a stable order. When nextCursor is not null, pass it back as cursor for the next page. It is null on the last page. The destination of the task is never listed; the worker reaches it through the tracked link.

Errors: 400 Invalid request (bad limit or cursor), 401, 429.

5.3 Claim a task

text
POST /api/v1/earn/tasks/{id}/claim
Content-Type: application/json

{id} is the task id.

Body fieldTypeRules
externalUserIdstringRequired. 1 to 128 characters, no leading or trailing spaces, no control characters. No other fields are allowed.
JSON
{ "externalUserId": "w_9f3a1c2e" }

Success, 201 Created:

JSON
{
  "success": true,
  "claimId": "clclaim000001",
  "expiresAt": "2026-10-07T14:30:00.000Z",
  "redirectUrl": "https://www.pawaboost.com/r/AbCdEfGh1234"
}

Errors:

StatuserrorNotes
400Invalid requestBody is not JSON, has extra fields, or externalUserId is invalid.
401Unauthorized
403This worker is not allowedThe worker is blocked.
404Task not availableThe task is finished, paused, or the id is wrong.
409No slots remaining for this task
409This worker has already claimed this task
409Claim limit reached for this task
429Too many requests
503Please retryWith Retry-After.

Notes: redirectUrl is returned only here. If you lose it, the claim cannot be used; wait for it to expire and claim again.

5.4 Claim status

text
GET /api/v1/earn/claims/{id}

{id} is the claimId. You can only read your own claims.

JSON
{
  "success": true,
  "claimId": "clclaim000001",
  "taskId": "cltask000001",
  "status": "OPEN",
  "expiresAt": "2026-10-07T14:30:00.000Z",
  "linkOpened": true
}
FieldNotes
statusOPEN, SUBMITTED, APPROVED, REJECTED, EXPIRED or CANCELLED. A claim past expiresAt is reported as EXPIRED.
linkOpenedtrue once the worker has opened the tracked link.

Errors: 401, 404 Not found (unknown id, or not your claim, both identical), 429.

5.5 Submit proof

text
POST /api/v1/earn/claims/{id}/submit
Content-Type: multipart/form-data

{id} is the claimId. Send the proof as a multipart form. Each field may appear once and no other fields are accepted.

FieldTypeRules
screenshotfileOptional. JPEG, PNG or WebP, at most 2 MB. The file contents are checked, not the extension.
proofUsernametextOptional. Up to 200 characters.
proofUrltextOptional. Must start with http:// or https://, up to 2048 characters. Stored for review, never visited.
selectedCommenttextOptional. Up to 1000 characters.
Linux / macOS
curl -s -X POST "$BASE/api/v1/earn/claims/clclaim000001/submit" \
  -H "Authorization: Bearer $KEY" \
  -F "screenshot=@proof.png" \
  -F "proofUsername=worker_handle"

Success, 201 Created:

JSON
{
  "success": true,
  "submissionId": "clsub0000001",
  "status": "PENDING"
}

Nothing is paid at this point. The submission waits for review.

Which proof a task needs. It depends on the task type, for example a screenshot, a username, a link, or a combination. If something required is missing you get 400 Missing required proof: <field> where the field is screenshot, proofUsername, proofUrl, screenshot or proofUrl, or proof (at least one proof field is always needed). You can fix it and submit again on the same claim.

Watch-time tasks. When durationSeconds is set, proof is refused with 409 The required watch time has not elapsed yet until that many seconds have passed since the worker opened the link. Wait and retry.

Duplicates. Every proof image is compared with images already submitted. The same screenshot cannot be used twice, including a copy that was merely saved again or re-compressed. A repeat returns 409 This proof has already been submitted. Each worker must use their own, fresh screenshot.

What to tell workers about good screenshots.

  • Take it after doing the action, so the result is visible (for example the "Following" button).
  • Show the whole screen or the relevant part, not a tiny crop.
  • Make the account name and the action clearly readable.
  • Do not edit, crop out information, reuse someone else's image, or submit an old screenshot.
  • Keep it under 2 MB. Screenshots from a phone are usually fine; if not, save as JPEG.

Errors:

StatuserrorNotes
400Invalid requestNot multipart, unknown or repeated field, bad text field.
400Invalid imageNot a valid JPEG, PNG or WebP.
400Missing required proof: <field>See above.
401Unauthorized
403This worker is not allowed
404Not foundUnknown claim, or not yours.
409This claim can no longer accept a submissionExpired, cancelled, or already submitted.
409Open the task link before submitting proof
409The required watch time has not elapsed yet
409Task not availableThe task closed.
409This task cannot accept submissions
409This proof has already been submitted
413Image is too large (maximum 2 MB)
429Too many requests
429Too many new workers todayDaily limit on first-time workers. Wait the Retry-After time.
503Please retryWith Retry-After.

5.6 Submission status

text
GET /api/v1/earn/submissions/{id}

{id} is the submissionId. You can only read your own submissions.

JSON
{
  "success": true,
  "submissionId": "clsub0000001",
  "claimId": "clclaim000001",
  "taskId": "cltask000001",
  "externalUserId": "w_9f3a1c2e",
  "status": "PENDING",
  "rewardKobo": "3900",
  "submittedAt": "2026-10-07T14:05:11.000Z",
  "reviewedAt": null,
  "reversed": false
}
FieldNotes
statusPENDING, APPROVED or REJECTED.
rewardKoboDecimal string. The value of this submission in kobo.
submittedAtWhen you submitted.
reviewedAtnull while PENDING.
reversedtrue if an approved submission was later reversed. status stays APPROVED.
rejectionReasonPresent only when status is REJECTED.

A rejected submission:

JSON
{
  "success": true,
  "submissionId": "clsub0000002",
  "claimId": "clclaim000002",
  "taskId": "cltask000001",
  "externalUserId": "w_41be77aa",
  "status": "REJECTED",
  "rewardKobo": "3900",
  "submittedAt": "2026-10-07T14:06:30.000Z",
  "reviewedAt": "2026-10-07T15:22:10.000Z",
  "reversed": false,
  "rejectionReason": "Screenshot does not show the follow"
}

Errors: 401, 404 Not found (unknown id, or not yours, both identical), 429.

5.7 Balance

text
GET /api/v1/earn/balance

No parameters.

JSON
{
  "success": true,
  "balanceKobo": "125000",
  "totalEarnedKobo": "200000",
  "totalReversedKobo": "5000",
  "totalSettledKobo": "70000",
  "ledger": [
    { "type": "SETTLEMENT", "amountKobo": "70000", "createdAt": "2026-10-07T16:00:00.000Z", "reference": "BANK-TRF-0091" },
    { "type": "REVERSAL", "amountKobo": "5000", "createdAt": "2026-10-06T10:12:00.000Z", "reference": null },
    { "type": "CREDIT", "amountKobo": "3900", "createdAt": "2026-10-05T09:30:00.000Z", "reference": null }
  ]
}
FieldNotes
balanceKoboWhat PawaBoost currently owes you. Equals earned minus reversed minus settled. Can be negative.
totalEarnedKoboSum of all approvals credited.
totalReversedKoboSum of all reversals.
totalSettledKoboSum of all payouts to you.
ledgerYour 20 most recent entries, newest first.

All amounts are strings. A partner with no activity yet gets zeros and an empty ledger. See section 9 for what each entry type means.

Errors: 401, 429.

5.8 List submissions

text
GET /api/v1/earn/submissions
Query parameterTypeRules
externalUserIdstringOptional. Only this worker's submissions. Same rules as when claiming.
statusstringOptional. Exactly PENDING, APPROVED or REJECTED (upper case).
limitintegerOptional. 1 to 50. Default 20.
cursorstringOptional. The nextCursor of the previous page. Must be one of your own submissions.
Linux / macOS
curl -s "$BASE/api/v1/earn/submissions?status=PENDING&limit=20" -H "Authorization: Bearer $KEY"
JSON
{
  "success": true,
  "submissions": [
    {
      "submissionId": "clsub0000001",
      "claimId": "clclaim000001",
      "taskId": "cltask000001",
      "externalUserId": "w_9f3a1c2e",
      "status": "PENDING",
      "rewardKobo": "3900",
      "submittedAt": "2026-10-07T14:05:11.000Z",
      "reviewedAt": null,
      "reversed": false
    }
  ],
  "nextCursor": "clsub0000001"
}

Newest first. Each item has the same fields as 5.6, including rejectionReason on rejected items only. When nextCursor is not null, pass it back as cursor to get the next page; it is null on the last page. Remember to URL-encode externalUserId.

Errors: 400 Invalid request (any invalid query value, or a cursor that is not one of your submissions), 401, 429.


6. Error reference

Every error has the form { "success": false, "error": "<message>" }. "Retry?" says whether sending the same request again can succeed.

StatusMessageMeaningRetry?
400Invalid requestBad body, query parameter, field or cursor.No. Fix the request.
400Invalid imageScreenshot is not a valid JPEG, PNG or WebP.No. Send a valid image.
400Missing required proof: <field>The task requires that proof field.After adding it.
401UnauthorizedKey missing, wrong, revoked, or partner suspended.No. Check the key; contact support if it used to work.
403This worker is not allowedThis worker cannot take part. No reason is given.No. Stop offering tasks to this worker.
404Not foundThe claim or submission does not exist, or is not yours.No.
404Task not availableThe task is not open for claims.No. Choose another task.
409No slots remaining for this taskAll slots are taken.Later, or another task.
409This worker has already claimed this taskThe worker has an active or approved claim on it.No. Read the existing claim.
409Claim limit reached for this taskA claim limit was reached for your account on this task.Later, when claims finish or expire.
409This claim can no longer accept a submissionClaim expired, was cancelled, or already has a submission.No. Read the claim state.
409Open the task link before submitting proofThe worker has not opened the tracked link.After the worker opens it.
409The required watch time has not elapsed yetSubmitted too early.Yes, after the wait.
409Task not availableThe task closed before the proof arrived.No.
409This task cannot accept submissionsThe task has no payable reward.No.
409This proof has already been submittedDuplicate screenshot.No. A new screenshot is needed.
413Image is too large (maximum 2 MB)File over 2 MB.After shrinking it.
429Too many requestsRate limited. Retry-After gives the seconds to wait.Yes, after Retry-After.
429Too many new workers todayDaily limit on first-time workers. Retry-After is sent.Yes, after Retry-After.
500Something went wrongUnexpected error on our side.Yes, with backoff (see the safety rules in section 7).
503Please retryTemporary contention. Retry-After is sent.Yes, after Retry-After.
503Service unavailableTemporary problem on our side.Yes, with backoff.

7. Rate limits and retries

Limits and headers

Each key may make 30 requests per minute. Every authenticated response includes:

HeaderMeaning
X-RateLimit-LimitRequests allowed per window.
X-RateLimit-RemainingRequests left in this window.
X-RateLimit-ResetWhen the window ends, in Unix seconds.

Over the limit you receive 429 Too many requests with Retry-After (seconds). Treat the limit as burst protection. Stay well below it, spread bulk work out, and slow down when X-RateLimit-Remaining gets low.

Backoff

  • Honour Retry-After when present.
  • Otherwise use exponential backoff with jitter: wait about 1 s, 2 s, 4 s, 8 s, up to a cap of about 30 s, with a random +/- 50% each time.
  • Stop after a handful of attempts and surface an error. Never retry in a tight loop.
  • Do not retry 400, 401, 403, 404 or 409 unchanged. They will fail the same way.

What is safe to retry

EndpointSafe to retry?Notes
GET endpoints (ping, tasks, claim status, submission status, list, balance)Yes, alwaysRead-only.
POST .../claimYes, with careA 503 means nothing was recorded, so retry. After a timeout or 500 the outcome is unknown: the retry may return 409 This worker has already claimed this task, which means the first call worked, but its redirectUrl is lost. That claim will expire; claim again afterwards.
POST .../submitYes, with careA 503 means nothing was recorded. After a timeout or 500, call GET /claims/{id} first: if it is SUBMITTED the proof arrived, so do not send it again (a repeat gets a 409).

A 409 that says "already" is not a failure to retry. It means an earlier request took effect, so read the current state instead.

Sample retry code: JavaScript

JavaScript
// Node 18+ (global fetch). Retries only 429, 500 and 503, and only when it is safe.
async function callApi(url, options = {}, maxAttempts = 5) {
  for (let attempt = 1; ; attempt++) {
    let res;
    try {
      res = await fetch(url, {
        ...options,
        headers: { ...options.headers, Authorization: `Bearer ${process.env.PAWABOOST_KEY}` },
      });
    } catch (err) {
      if (attempt >= maxAttempts) throw err; // network error
      await sleep(backoff(attempt));
      continue;
    }

    if (![429, 500, 503].includes(res.status) || attempt >= maxAttempts) return res;

    const retryAfter = Number(res.headers.get("retry-after"));
    await sleep(retryAfter > 0 ? retryAfter * 1000 : backoff(attempt));
  }
}

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
// 1s, 2s, 4s, 8s ... capped at 30s, with +/- 50% jitter.
const backoff = (attempt) => Math.min(30000, 1000 * 2 ** (attempt - 1)) * (0.5 + Math.random());

Sample retry code: PHP

PHP
<?php
// PHP 7.4+ with the cURL extension. Retries only 429, 500 and 503.
function callApi(string $url, array $curlOptions = [], int $maxAttempts = 5): array
{
    for ($attempt = 1; ; $attempt++) {
        $retryAfter = 0;
        $ch = curl_init($url);
        curl_setopt_array($ch, $curlOptions + [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('PAWABOOST_KEY')],
            CURLOPT_HEADERFUNCTION => function ($ch, $line) use (&$retryAfter) {
                if (stripos($line, 'retry-after:') === 0) {
                    $retryAfter = (int) trim(substr($line, 12));
                }
                return strlen($line);
            },
        ]);
        $body = curl_exec($ch);
        $status = (int) curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
        curl_close($ch);

        $retryable = $body === false || in_array($status, [429, 500, 503], true);
        if (!$retryable || $attempt >= $maxAttempts) {
            return ['status' => $status, 'body' => $body === false ? null : json_decode($body, true)];
        }

        $delay = $retryAfter > 0
            ? $retryAfter
            : min(30, 2 ** ($attempt - 1)) * (0.5 + mt_rand() / mt_getrandmax());
        usleep((int) ($delay * 1000000));
    }
}

8. Best practices and integration checklist

Polling for status

  • Submissions are reviewed by people, so results are not instant. Do not poll faster than every 30 seconds; every few minutes is plenty.
  • Prefer one list call over many single calls: GET /submissions?status=PENDING&limit=50 gives all waiting items at once.
  • Stop polling a submission once it is APPROVED or REJECTED; those do not change, except that an approval may later show reversed: true.
  • Check the whole list for changes now and then rather than only the items you remember.

Showing workers their status

API stateSuggested wording to the worker
Claim OPEN, link not opened"Open the task link to start."
Claim OPEN, link opened"Do the task, then upload your screenshot before expiresAt."
Submission PENDING"Under review."
Submission APPROVED"Approved. Your reward is on its way." (credit the worker per your own rules.)
Submission REJECTED"Not approved: <rejectionReason>." You may offer another try.
Claim EXPIRED"Time ran out. You can start the task again."

Handling rejection reasons

  • rejectionReason is written to be shown to your worker. Show it as it is, and do not parse it; the wording can change.
  • Do not credit a worker for a rejected submission.
  • A rejected worker may claim the task again if slots remain. Limit repeated attempts on your side to avoid wasted effort.

Handling expired claims

  • Expiry is normal. Treat EXPIRED as "try again", not as an error.
  • Show a countdown from expiresAt so the worker knows the deadline.
  • Do not hold workers on claims they will not finish; an unfinished claim blocks a slot that others could use.

Paying your workers

  • Credit your worker only after the submission is APPROVED, and consider holding the payment until you are sure it will not be reversed (see section 9).
  • Remember that PawaBoost pays you, in settlements, not per submission. Keep enough cash flow to pay workers before the next settlement.

Going-live checklist

  • ☐ The key is stored on the server and is not in any client code or repository.
  • ☐ GET /ping returns ACTIVE from the production server.
  • ☐ Worker ids are stable, anonymous hashes. No names, emails or phone numbers.
  • ☐ The worker, not your server, opens redirectUrl.
  • ☐ redirectUrl is passed to the worker immediately; it cannot be fetched again.
  • ☐ Screenshots are checked for type (JPEG, PNG or WebP) and size (2 MB) before upload.
  • ☐ Retries use backoff, honour Retry-After, and never repeat a 4xx.
  • ☐ Money is handled as integer kobo or big integers, never floats.
  • ☐ Polling is no faster than every 30 seconds.
  • ☐ You handle 403 This worker is not allowed by stopping tasks for that worker.
  • ☐ You handle 401 by alerting your team, not by retrying in a loop.
  • ☐ You reconcile GET /balance against your own records regularly.

9. Wallet, reversals and settlement

Reading the balance

GET /balance returns four totals and your 20 most recent ledger entries.

text
balanceKobo = totalEarnedKobo - totalReversedKobo - totalSettledKobo

The ledger is an append-only record. Entries are never edited or deleted. A correction is always a new entry.

Ledger entry types

typeMeaningEffect on balance
CREDITA submission was approved and its reward credited to you.Increases
REVERSALAn earlier approval was taken back.Decreases
SETTLEMENTPawaBoost paid out part or all of your balance to you.Decreases

amountKobo is always positive. The type tells you the direction.

Reversals and negative balances

If an approved submission is later found to be invalid, it is reversed:

  • the submission keeps status: "APPROVED" and shows reversed: true;
  • a REVERSAL entry is added to your ledger and totalReversedKobo grows;
  • balanceKobo goes down by the reward.

If your balance was already paid out, the balance can become negative. A negative balance is not a separate bill. It is simply netted: new approvals first bring the balance back up, and the next settlement is calculated on what is left. Because a reversal can arrive after an approval, hold your own worker payments for a sensible period before treating a reward as final.

Settlement

PawaBoost pays your balance out to you separately, outside the API. When it does, a SETTLEMENT entry is added, totalSettledKobo grows, and balanceKobo goes down by the amount paid. The entry's reference is the payment reference recorded for that payout, for example a bank transfer reference. Use it to match the payout to your bank statement. The reference is null for CREDIT and REVERSAL entries.

The ledger shows only your 20 latest entries, so keep your own record of references as you see them.


10. Data handling and privacy

  • Proofs are deleted after review. A screenshot is kept only long enough to review it. Once the submission is approved or rejected, the image is deleted. We keep the decision, not the picture. We cannot return a deleted image, so keep your own copy if you need one.
  • No worker personal data is requested. The API only needs an opaque worker id. Do not send real names, emails, phone numbers or social handles as externalUserId.
  • What you may see about a rejection is limited to a short, worker-friendly reason. Internal review details are never shown.
  • Proof text (proofUsername, proofUrl, selectedComment) is used for review only. Do not put private information in it.
  • Screenshots may show personal content. Tell workers to crop or avoid showing private messages, notifications and other people's details, as long as the proof needed for the task stays visible.
  • You are responsible for the lawful handling of your own users' data on your side, including your agreement with them.

11. FAQ and troubleshooting

1. My submit returns 409. What does it mean?

Read the message. Open the task link before submitting proof: the worker has not opened redirectUrl. The required watch time has not elapsed yet: wait for durationSeconds after the link was opened. This claim can no longer accept a submission: the claim expired or already has a submission. This proof has already been submitted: the screenshot was used before; a new one is needed. Call GET /claims/{id} to see the claim's state.

2. I get 403 "This worker is not allowed".

That worker cannot take part, and no reason is given. Stop offering tasks to that worker. Other workers are not affected.

3. My worker's claim expired. What now?

The slot was released. The worker can claim the task again with a new claim, if slots remain. Show the countdown so it does not happen again.

4. My balance is negative.

A reversal was applied after earlier earnings had already been settled. It is netted automatically: new approvals bring the balance back up and the next settlement is based on what remains. See section 9.

5. I lost the redirectUrl.

It is shown only once and cannot be fetched again. Let that claim expire (the claim call for the same worker returns 409 This worker has already claimed this task until then) and claim again.

6. All my requests return 401.

Check the header is exactly Authorization: Bearer <key>, that the key is complete, and that you use the production key on production. A revoked key or a suspended partner account also returns 401, with no further detail. Contact support if a key that worked has stopped. You can check your keys, and whether the key is revoked, on the Partner API page.

6b. I cannot see the Partner API page, or "New API Key" is greyed out.

No Partner API page: your PawaBoost account has not been linked to your partner yet. Ask support to link it (send your partner name and account email). "New API Key" greyed out: you already have 3 active keys (revoke one), or your partner account is suspended, in which case the page is read-only.

6c. How do I get or rotate an API key?

Create it yourself on the Partner API page (see Getting your API key). To rotate, create the new key first, switch your server over, confirm it works, then revoke the old one.

7. I get 429. How long do I wait?

Use the Retry-After header (seconds). Reduce your request rate and spread bulk calls. Too many new workers today is a daily limit on first-time workers; it clears with time.

8. My screenshot is rejected with 400 "Invalid image".

The file is not a real JPEG, PNG or WebP. The contents are checked, so renaming a different file type does not work. Convert it or take a new screenshot.

9. I get 413 "Image is too large".

The limit is 2 MB. Ask workers to use a normal phone screenshot, or compress it, before uploading.

10. The task list is empty.

No task currently has free slots, or all of them were claimed. Try again later.

11. A submission was rejected. Can the worker try again?

Yes, if slots remain. They need a new claim and a new, genuine screenshot.

12. An approved submission now says reversed: true.

It was found to be invalid after approval and was taken back. A REVERSAL entry is in your ledger. The worker cannot claim that task again.

13. A submit call timed out. Was it received?

Call GET /claims/{id}. If the status is SUBMITTED, the proof arrived. Do not send it again.

14. A submission has been PENDING for a long time.

Reviews are done by people and can take a while. Keep polling gently. A submission that is never reviewed is closed as rejected after a few days, and the worker may try again.

15. GET /submissions returns 400 with a cursor.

The cursor must be exactly a nextCursor value you received, from your own list. If it no longer works, start again from the first page.


12. Versioning, changelog and support

Versioning

This is version 1, served under /api/v1/. Within v1 we only make backwards-compatible changes: new endpoints, new optional fields and new response fields. Write your client to ignore fields it does not know. A breaking change would be released as a new version under a new path, with notice.

Changelog

DateChange
2026-10-10Partners now create and revoke their own API keys on the Partner API page (see "Getting your API key").
2026-10-07Added GET /submissions, GET /submissions/{id} and GET /balance. Rewrote this guide and added a Postman collection.
EarlierGET /ping, GET /tasks, POST /tasks/{id}/claim, GET /claims/{id}, POST /claims/{id}/submit.

Postman

A ready-made collection is in docs/partner-api-postman.json. Import it into Postman and set the baseUrl and apiKey collection variables. Keep the key out of shared workspaces.

Support

Contact PawaBoost support through either channel:

  • Telegram: https://t.me/pawaboostsupport
  • Email: support@pawaboost.com

Contact support for: linking your PawaBoost account to your partner, problems creating or revoking keys, a worker that is blocked, balance or settlement questions, and anything you suspect is wrong (unexpected 401 or 403 responses, missing credits, a reversal you do not understand).

When you write, include:

  • your partner name
  • the claimId or submissionId
  • the time of the request in UTC
  • the HTTP status and error message you received

Never send your API key. Support will never ask for it.