Upsert invoice by external ID

Create or update an invoice identified by external source and ID. Used by integrations (PracticeHub, Wodify) to sync invoices. --- **Related endpoints** - `PUT /invoices/external/batch` — Batch upsert invoices by external ID - `GET /invoices` — List invoices - `POST /invoices` — Create invoice - `GET /invoices/{id}` — Get invoice - `PATCH /invoices/{id}` — Update invoice - `DELETE /invoices/{id}` — Delete invoice - `POST /invoices/{id}/margin-estimate` — Estimate invoice net by payment rail - `POST /invoices/{id}/refund` — Refund invoice **Common errors** - `400 invalid_request` — malformed payload or failed validation. - `409 conflict` — Idempotency-Key collision with a different body, or a concurrent state-transition conflict. - `422 unprocessable_entity` — business-rule failure (for example, refunding more than the original charge). **Idempotency** Pass an `Idempotency-Key` header (UUID v4 recommended) to make retries safe. Keys are valid for 24 hours; see [the idempotency guide](/docs/fundamentals/idempotency).

PUT
/invoices/external/{source}/{externalId}

Create or update an invoice identified by external source and ID. Used by integrations (PracticeHub, Wodify) to sync invoices.


Related endpoints

  • PUT /invoices/external/batch — Batch upsert invoices by external ID
  • GET /invoices — List invoices
  • POST /invoices — Create invoice
  • GET /invoices/{id} — Get invoice
  • PATCH /invoices/{id} — Update invoice
  • DELETE /invoices/{id} — Delete invoice
  • POST /invoices/{id}/margin-estimate — Estimate invoice net by payment rail
  • POST /invoices/{id}/refund — Refund invoice

Common errors

  • 400 invalid_request — malformed payload or failed validation.
  • 409 conflict — Idempotency-Key collision with a different body, or a concurrent state-transition conflict.
  • 422 unprocessable_entity — business-rule failure (for example, refunding more than the original charge).

Idempotency

Pass an Idempotency-Key header (UUID v4 recommended) to make retries safe. Keys are valid for 24 hours; see the idempotency guide.

x-api-key<token>

Your RevKeen merchant API key. Create and manage keys in Dashboard → Settings → Developer. Use rk_sandbox_* for staging/test and rk_live_* for production. The same key may be sent as Authorization: Bearer <key> if that suits your HTTP client better. A missing, invalid, expired, or revoked key returns 401 with a WWW-Authenticate: Bearer challenge; a valid key without the required scope returns 403.

In: header

Path Parameters

source*string

External source identifier (e.g., practicehub, wodify)

externalId*string

External ID from the source system

Request Body

application/json

Invoice data for upsert. external_id and external_source are set from path params.

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

Stuck on an error response? Ask the RevKeen assistant to explain it.
curl -X PUT "https://api.revkeen.com/v2/invoices/external/practicehub/INV-12345" \
  -H "x-api-key: $REVKEEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_external_ref": {
      "source": "string",
      "id": "string"
    },
    "customer_uuid": "00000000-0000-0000-0000-000000000000",
    "invoice_number": "string",
    "total_minor": 0,
    "subtotal_minor": 0,
    "tax_minor": 0,
    "discount_minor": 0,
    "currency": "USD",
    "invoice_date": "string",
    "due_date": "string",
    "status": "string",
    "line_items": [
      {
        "description": "string",
        "quantity": 1,
        "unit_amount_minor": 0,
        "product_id": "00000000-0000-0000-0000-000000000000"
      }
    ],
    "notes": "string",
    "metadata": {},
    "custom_fields": {},
    "subscription_terms": {
      "collection_method": "charge_automatically",
      "start_mode": "when_paid",
      "start_date": "string",
      "duration_type": "until_cancelled",
      "duration_count": 12,
      "end_date": "string",
      "first_payment_behavior": "charge_first_cycle_now"
    },
    "external_updated_at": "2026-01-01T00:00:00Z",
    "external_type": "string"
  }'
{  "data": {    "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",    "customer_uuid": "e7eefd45-cb13-4c62-b229-e5bbc1362123",    "invoice_number": "string",    "total_minor": 0,    "currency": "string",    "allowed_methods": [      "string"    ],    "status": "string",    "due_date": "string",    "custom_fields": {},    "external_source": "string",    "external_type": "string",    "external_id": "string",    "subscription_terms": {      "collection_method": "charge_automatically",      "start_mode": "when_paid",      "start_date": "string",      "duration_type": "until_cancelled",      "duration_count": 1,      "end_date": "string",      "first_payment_behavior": "charge_first_cycle_now"    },    "created_at": "2019-08-24T14:15:22Z",    "updated_at": "2019-08-24T14:15:22Z"  },  "created": true,  "warnings": [    "string"  ],  "requestId": "string"}

Batch upsert invoices by external ID PUT

Create or update multiple invoices by external system ID. Supports up to 100 invoices per request with stale update protection and immutable field guardrails. --- **Related endpoints** - `GET /invoices` — List invoices - `POST /invoices` — Create invoice - `GET /invoices/{id}` — Get invoice - `PATCH /invoices/{id}` — Update invoice - `DELETE /invoices/{id}` — Delete invoice - `POST /invoices/{id}/margin-estimate` — Estimate invoice net by payment rail - `POST /invoices/{id}/refund` — Refund invoice - `POST /invoices/{id}/reject` — Reject invoice **Common errors** - `400 invalid_request` — malformed payload or failed validation. - `401 authentication_error` — missing, invalid, expired, or revoked credential. Codes: `authentication_failed`, `invalid_api_key`, `expired_api_key`, `api_key_revoked`, `session_invalid`, `merchant_required`. Carries a `WWW-Authenticate: Bearer` challenge. - `403 authorization_error` — the caller is identified but the action is denied. Codes include `insufficient_permissions`, `ip_not_allowed`, `merchant_mismatch`, and `origin_not_allowed`. **Idempotency** Pass an `Idempotency-Key` header (UUID v4 recommended) to make retries safe. Keys are valid for 24 hours; see [the idempotency guide](/docs/fundamentals/idempotency).

Finalize an invoice POST

Finalizes a draft invoice, locking it for payment. Assigns invoice number and generates public token. After finalization, financial fields become immutable. --- **Related endpoints** - `PUT /invoices/external/batch` — Batch upsert invoices by external ID - `GET /invoices` — List invoices - `POST /invoices` — Create invoice - `GET /invoices/{id}` — Get invoice - `PATCH /invoices/{id}` — Update invoice - `DELETE /invoices/{id}` — Delete invoice - `POST /invoices/{id}/margin-estimate` — Estimate invoice net by payment rail - `POST /invoices/{id}/refund` — Refund invoice **Common errors** - `400 invalid_request` — malformed payload or failed validation. - `404 resource_missing` — the referenced resource does not exist or is not visible to your key. **Idempotency** Pass an `Idempotency-Key` header (UUID v4 recommended) to make retries safe. Keys are valid for 24 hours; see [the idempotency guide](/docs/fundamentals/idempotency).