Working with a coding agent? Point it at earnesty.app/docs/integration/llms-full.txt — all public integration guides in one Markdown file, no key required.

Processing credits

See the integration overview for the full integration contract.

Configure and fund an offering

Your system owns end-user rewards; the Earnesty organization wallet pays processing fees. The processing fee is 5 Earnesty Credits per accepted validation on every platform, including its later settlement check. Every $1 buys 100 credits. Registration is free.

  1. Configure the reward endpoint and supported reward types, then test delivery to an account of your own. Delivery must be idempotent by rewardReference; follow the complete endpoint contract, including revocations.
  2. In Billing, purchase at least $10 for 1,000 credits, or claim the introductory promotion if available. A pending payment is not spendable balance.
  3. Ongoing rewards and Milestones use available purchased or promotional credits. A card is optional. For automatic replenishment, enable auto-recharge with an explicit monthly spending ceiling. Low-balance emails prompt manual funding when auto-recharge is off.
  4. For a Drop, choose its dates, unique tag, reward and number of places. The places are a cap on how many posts the Drop rewards, not a reservation: each accepted Drop post is charged from the available balance, like any other offer. A time-only Drop’s cap is the number of selected participants, and adding participants raises it without reserving anything. Activating a Drop needs only enough available credits for one check. Drops do not require auto-recharge, and a Drop pauses like any offer when the wallet cannot cover a check.
  5. Enroll users from your backend and show the returned hosted reward-page link. Refresh the signed link when rendering; do not store it as a permanent URL.

Purchased funds do not expire. Promotional funds expire after 90 days and cannot be refunded. Eligible promotional funds are spent oldest first, for every offer type.

Registration is separate from earning availability

Register users with POST /v1/users, using your server-side API key, your appId and their productUserId. Registration is free and unlimited.

Enrollment does not guarantee an immediately available posting reward. Read the hosted page or GET /v1/status?t=… for current eligibility, funding and offers:

  • funding.available describes general reward funding. Cooldowns, offer terms and user eligibility still apply.
  • Drops have no funds of their own. When general funding is unavailable, no Drop accepts posts either, and the hosted page shows the Drop as not currently available.
  • Each Drop exposes its funding and user-specific fundingAvailable; Milestones expose their remaining terms and funding availability.

Show the hosted page whenever possible so these rules and recovery states stay current. If funding is paused, say that posting rewards are currently unavailable. A user’s existing product access and previously delivered rewards are managed by your app. Remaining Drop places are a live snapshot, not a reservation for the viewer.

Validate after posting

Tell users to press Validate after publishing. A Drop requires a validation request before its published closing time. Allocation follows authenticated validation receipt order, subject to eligibility; posting earlier alone does not reserve a place. Timely queued requests can finish after closing. The nightly sweep can use remaining capacity only while the Drop is open.

For a custom reward page, the current HTTP sequence is:

POST /v1/status/check-now
Content-Type: application/json

{"t":"SIGNED_STATUS_TOKEN","requestKey":"CLIENT_GENERATED_UUID"}

For an exact post, use POST /v1/status/submit with the same fields plus "url":"https://x.com/example/status/123456789". These endpoints authenticate with the signed user token, not your organization API key.

The response is HTTP 202 with queued, requestId, state, receivedAt and deadlineAt. This acknowledges the request; it does not acknowledge a reward. Persist the request key and, for exact submissions, the URL before sending. If transport fails, retry the same key and URL. Once a receipt exists, poll:

GET /v1/status/validation/REQUEST_ID?t=SIGNED_STATUS_TOKEN

Poll only while that request is pending, with bounded delays (the hosted page uses five seconds). A completed run can contain rejected or skipped candidates; show success only when a result has state: "accepted". Refresh the user’s status when processing finishes. Reward delivery to your backend happens separately and may still be retrying. Never credit your own user from a browser receipt.

After an expired-link response, obtain a fresh signed link for the same enrollment and resume the saved request. Keep recovery state scoped to the enrolled user and ignore late responses after switching users. Do not mint new request keys to work around a pending request or a transport error.

Insufficient funds and retrying the same post

A queue receipt does not reserve ordinary processing funds. If funds are insufficient when the worker checks or commits acceptance, the attempt fails; it does not wait for a top-up. After funding returns and the old request is terminal, submit the same post with a new request key while it is still within the validation window and eligible for its offer. The current window is 6 days, 23 hours and 30 minutes, and a receipt has a 10-minute recovery deadline. Reusing the old key returns the old receipt. Drops still require receipt before closing. See funding, deadlines and fee rules for the exact distinction, fee table and exceptions.

Stopping and refunds

An owner can stop new reward acceptance immediately, including active Drops. Already accepted posts still receive delivery and settlement. Unused purchased funds can be refunded; promotional funds never cash out. Stopping a program does not reverse rewards already delivered to your users.

Earnesty Credits and API amounts

The wallet counts Earnesty Credits, and one credit is bought for one USD cent. Amounts in credits are named for credits (availableCredits, processingPriceCredits). Amounts of money, such as a purchase, its tax or a refund, follow Stripe’s convention (amount, taxAmount): an integer in the currency’s smallest unit, with a lowercase ISO 4217 currency beside it. For example, availableCredits: 500 is 500 credits, currently enough for 100 X validations, and a $10 purchase is amount: 1000, currency: "usd". Earnesty Credits are separate from the rewards your app issues to its users.

Credit balances do not promise fixed validation counts. Platform rates may vary; future increases receive 30 days’ notice, and a change applies to every post accepted after it, Drop posts included. Purchased credits do not expire; promotional credits expire after 90 days. Refunds return the unused purchased value to the original payment, never promotional value or a recalculation using today’s validation rate.

Refunds in Billing

Payment history records payments and offers status refresh only for unresolved outcomes. A failed payment is labeled “Not paid — no funds added”; a new purchase starts in Add funds. Refund controls live in a separate wallet section showing the total refundable purchased credits and their USD value, including purchases older than the displayed payment history. Promotional credits and pending refund holds are excluded.

One confirmed request reserves the whole requested balance atomically, then allocates refunds to original payments. The same request key resumes the same allocation after interruption. No partial reservation is created if the available balance has changed. Provider returns may complete separately; refund history shows each original-payment return. Requests spanning more than 20 payments retain durable pending adjustments for the refund recovery worker. Auto-recharge remains an independent owner setting, with a warning to disable it before refunding if no further automatic purchases are wanted.

Multiple reward types

Use App settings → Reward types to define what the app grants. Each type has a permanent rewardType key and editable display names. Marketing can introduce a new type while drafting a Drop or Milestone. Confirm its mapping and test delivery in Integration before launch. Unknown keys must not silently grant the default currency. Handle idempotency by rewardReference for each delivery, regardless of type, and verify the test grants only once. Lifetime caps are independent per type; the config field maxLifetimePerUser controls the default type only.