API Docs
Guides

Approve payouts

Move a payout from created to approved in the dashboard, on a hosted screen, or through the API.

A payout created through the API starts in status created: it exists, but no money moves until the sending team approves it. Approval reserves the amount against the team balance. This split keeps the API safe by default: payouts:write can never move funds on its own.

After approval, sending the payout is a separate, explicit step. Send a claim link or pay a counterparty.

Who can approve

CredentialApproval through the API
Your own team's API keyOff by default. Talentir enables the payout.api_approve permission for your team on request.
An OAuth client acting for a customer's teamTypically not enabled. The customer approves on a hosted screen.

Without the permission, approval is a human step: a team member approves in the dashboard or on a hosted approval screen. For platforms, the hosted approval screen is the recommended way. It keeps the decision to move money with your customer, so your platform never controls their funds and stays clear of the regulated activity of a licensed payment provider.

Option 1: hosted approval screen

Mint a screen for a member of the team with POST /sessions, type: "payout_approval", and a list of payoutIds. The member reviews and approves the batch on a Talentir-hosted page, then returns to your redirectUrl.

curl -X POST "$BASE_URL/sessions" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "payout_approval",
    "payoutIds": ["payout_0e4ba886-0bfe-4b6a-ae2e-d6d9d135dd1e"],
    "redirectUrl": "https://yourapp.com/done"
  }'

Your product shows "payouts ready", the customer clicks through, reviews, and approves. The screen requires the visitor to sign in and be a member of that team. Add branding: "platform" to show your own brand. See Pay on behalf of your customers for every session field.

Option 2: the dashboard

Team members with approval permission see created payouts under Payouts in the Talentir dashboard and approve them there. No integration work needed.

Option 3: the API

With the payouts:approve scope, call POST /payouts/{id}/approve, or create the payout with "andThen": "approve" to create and approve in one request.

curl -X POST "$BASE_URL/payouts/campaign-42/approve" \
  -H "Authorization: Bearer $TALENTIR_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "andThen": "send_claim_link" }'

The body is optional. andThen runs the next step in the same request: send_claim_link or pay (pay also needs payouts:write and a counterparty recipient). The request either does both steps or neither. The claim link email goes out only after the approval is saved. If it cannot be sent, the payout stays approved with claimLinkSentAt: null; call send-claim-link again. The {id} in the path is the payout_… id or your customId.

Automatic approval spends from the team's wallet without a human in the loop, so the team owner must first set a daily spending allowance. See Wallet and allowance.

Errors

CodeMeaning
PAYOUT_NOT_APPROVABLEThe payout is not in status created.
VERIFICATION_REQUIREDThe team is not ready to approve. details.missing names what is left, as in the missing of GET /team. For kyb, mint a kyb session.
INSUFFICIENT_BALANCEThe approved payouts would exceed the team balance; details carries total, required, and currency. Deposit first: GET /team/accounts lists the deposit instructions per currency.
ALLOWANCE_REQUIREDAutomatic approval needs a daily spending allowance set by the owner. Mint an allowance session.

Wallet and allowance

Approval and execution run against the team's wallet, a passkey wallet held by the team owner:

  • A team must finish wallet setup before its payouts can be approved or executed. The hosted flows prompt the owner automatically if the wallet is missing.
  • The owner can cap automated spending with a daily allowance; mint the hosted screen for it with POST /sessions and type: "allowance".

Batches

A payout run, such as a monthly creator payout, uses the batch forms of the same four calls. Each takes up to 100 items and answers with a list in request order.

EndpointBody
POST /payouts/batch{ "payouts": [ ... ] }, each item a POST /payouts body, andThen included
POST /payouts/approve{ "ids": [ ... ], "andThen": "send_claim_link" }
POST /payouts/send-claim-link{ "ids": [ ... ] }
POST /payouts/pay{ "ids": [ ... ] }
curl -X POST "$BASE_URL/payouts/approve" \
  -H "Authorization: Bearer $TALENTIR_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "ids": ["campaign-42", "campaign-43"], "andThen": "pay" }'
  • All or nothing. One failing item fails the whole request with that item's own code, and nothing is applied. The error carries index, the 0-based position of the item. Errors about the team, such as INSUFFICIENT_BALANCE or VERIFICATION_REQUIRED, have no index.
  • One balance check. A batch approve reserves the sum of all payouts in one decision.
  • ids take payout ids or customIds, each once. Pass explicit ids, not a filter: a payout created between your list call and your approve call must not slip in.
  • No batch object. There is no batch status and no batch event. Give the payouts of one run a tag to find them again with GET /payouts?tag=.
  • Settlement is per payout. A batch pay moves every payout to requested at once; payout.completed and payout.failed then arrive one by one.

After approval

Send the payout with a claim link or a push to a counterparty. Track progress via webhooks (payout.approved → payout.requested → payout.completed) or GET /payouts/{id}. A provider rejection surfaces as payout.failed with a failureReason; the payout keeps its approval and is paid again with pay, which then also needs payouts:approve. The full state machine is described in Payout lifecycle.