Skip to main content
This guide walks through a typical partner integration, step by step. It covers two tracks that share the same payment endpoints:
  • Track A, your own company. You pay your own contractors or employees.
  • Track B, client companies. Companies you onboard pay their own recipients.
Every request needs authentication. Your API key needs the permission group listed for each endpoint. Write permission includes read for the same group. See Errors for what each endpoint returns when something goes wrong. In every path or body, company_id is the company that pays: yours in Track A, the client’s in Track B.

1. Onboard a client company

Track B only. A company you create is linked to your partner account. You receive its webhooks and can act on it with your API key. Wait for approved before you create payrolls. You also receive a company.kyc_status_update webhook when the status changes.

2. Create and verify recipients

A recipient is someone the company pays: a contractor, an employee, or a vendor. You collect their details and documents, then send them through the API. Bitwage does not email the recipient, and they never sign in. Do this in order. The recipient_id from the create response is the user_id you send to the user endpoints.

Create the recipient

Send recipient_type of contractor or employee, and a worker object with their name, email, phone, date of birth, and address. Set external_id to your own ID for them. It must be unique within the company. A duplicate returns recipient-external-id-already-used.
The response recipient_id is the user you upload documents for. Keep it. Create each person with this endpoint. POST /api/user/create makes a user who is not linked to a company, and a later recipients/create with the same email fails with recipient-worker-email-already-exists. For a vendor, send recipient_type vendor and a vendor object instead of worker. The returned recipient_id is a company ID.

Upload documents

Call POST /api/user/document/upload once per document, with user_id set to the recipient_id. A failed image upload returns user_update_advanced_data_failed. These endpoints, along with POST /api/user/update and POST /api/user/kyc-initiate, use the legacy error body and do not take an idempotency key. Check GET /api/user/document/list before you upload the same document again.

Start verification

After the documents are uploaded, call POST /api/user/kyc-initiate with the user_id. Bitwage sends user.kyc_status_update when the status changes. You can also read kyc_verification_status from GET /api/user/detail. It is pending, approved, rejected, unapproved, or neutral (manual review). Some paying companies require every recipient to be approved before a payroll is accepted. In that case payroll creation returns a 422 saying the recipients must have approved KYC.

3. Add payment destinations

A distribution is where a recipient is paid: a crypto address or a bank account. A recipient can have several, and each payment is split across them by percentage (the allocation).
  1. For a bank account, call GET /api/user/distribution/fields and send exactly those fields in distribution_data.
  2. Create the distribution. The response includes its current allocation.
  3. Call the allocations endpoint so the allocations of the recipient’s distributions add up to 100.

4. Pay recipients

  1. Optionally estimate fees. For a balance account funding method, pass the returned quote id as quote_id when you create the payroll to lock the rate.
  2. Create the payroll with a to_pay item for each recipient. Each item has either user_id or company_id.
  3. Always send funding_method and an external_id. Partners can’t set a company default, so a request that omits funding_method fails with a 422.
  4. Keep the payroll_id from the response. This response is the only creation signal. There is no creation webhook.
  5. Fund the payroll as the funding method describes. If a crypto quote expires first, refresh it.

Pay vendors

Vendor payments use quotes, invoice uploads, and a separate create call. These endpoints support API key authentication only.

5. Track the payroll

You can follow a payroll by webhook, by polling, or both. Webhooks are sent once and aren’t retried. Use them for speed and the GET endpoints as the source of truth. See Webhooks for the payloads, ordering, and signature validation.

Production checklist

  • Send an Idempotency-Key on every endpoint marked Yes or Required. See Idempotency.
  • Store payroll_id, your external_id, and each subpayroll_id.
  • Branch on the error code, not on message. See Errors.
  • Verify the x-bitwage-signature header on every webhook.
  • Reconcile open payrolls with GET /api/company/{company_id}/payrolls on a schedule, in case a webhook was missed.