CRM Solid logo
GUIDE16 min read

How to sync external sales into your CRM revenue ledger

A step-by-step guide to connecting WooCommerce, Shopify, a custom site, or any SaaS product to the CRM Solid Finance ledger via push API key or scheduled pull feed - with automatic contact matching, idempotent deduplication, and per-source profit and loss reporting.

14-day free trial · No credit card required · Cancel anytime

What you will learn

Four revenue-sync skills by the end of this guide

Push with rsk_ keys

POST sale events from any backend using a scoped Bearer token that is stored securely and never re-exposed.

Pull from a feed URL

Let CRM Solid poll your existing sales feed on a schedule - no code change required on your platform.

Auto contact matching

Every sale is matched to a CRM contact by email, enriching the record with purchase history automatically.

Per-source P&L

See daily profit and loss per source - income minus fees and expense events - in a single Finance view.

What you will need

Connecting your first revenue source takes about 15 minutes if you already have server-side access to your external site. The checklist below covers the decisions you need to make first.

  • A CRM Solid workspace on the Pro or Business plan (free trial works).
  • Access to the Finance module in the panel (Finance > Revenue sources).
  • For push mode: the ability to add an HTTP POST call to your site backend on the "order completed" event.
  • For pull mode: an existing feed URL on your site that returns paginated sale events as JSON.
  • The currency code(s) your sales use (ISO 4217, e.g., USD, EUR, GBP).
  • Optional: customer email in your order records, for automatic CRM contact matching.

Step 1: Create a revenue source in CRM Solid

Budget: 1 minute. In CRM Solid, go to Finance > Revenue sources > New source. Give the source a recognizable name - "WooCommerce store", "Shopify UK", or "Custom PHP site" all work. The name appears on every ledger entry that comes from this source, so pick something you will recognize at a glance six months later.

Choose Push or Pull mode. You can add a second source of the other type later if you want both. Save. CRM Solid creates an isolated record and you land on the source detail page.

Step 2: Generate an rsk_ API key (push mode)

Budget: 1 minute. In the source detail screen, open the API key tab and click Generate key. The panel shows the raw key once, in the format rsk_live_xxxxxxxxxxxxxxxx. Copy it now.

Store the key as an environment variable on your server (e.g.,CRM_SOLID_RSK_KEY). Never commit it to source control. CRM Solid stores only a BCrypt hash of the key - it cannot be retrieved from the panel again. If you lose it, generate a new one; old keys can be revoked from the same tab.

Security note: the rsk_ key is scoped to revenue event ingestion only. A leaked key cannot read contacts, send messages, or access any other part of the API.

Step 3: POST your first sale event

Budget: 5 minutes. From your site backend, send a POST request to https://api.crmsolid.com/public/v1/revenue/events with a JSON body. Below is a realistic example using curl:

curl -X POST https://api.crmsolid.com/public/v1/revenue/events \
  -H "Authorization: Bearer rsk_live_YOUR_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "externalId":  "wc_10482",
    "type":        "income",
    "status":      "completed",
    "amount":      129.00,
    "currency":    "USD",
    "occurredAt":  "2026-06-04T14:32:18Z",
    "tax":         21.50,
    "fee":         4.07,
    "product":     "Pro Plan",
    "sku":         "PRO-001",
    "quantity":    1,
    "unitPrice":   129,
    "discount":    0,
    "coupon":      "SPRING",
    "customer": {
      "externalId": "cust_77",
      "email":      "[email protected]",
      "name":       "Sara Miller",
      "country":    "US"
    },
    "metadata": { "orderTags": ["vip"] }
  }'

Only three fields are required: externalId, amount, and occurredAt. Every other field is optional. Send as much as you have:

  • externalId - your own order or transaction ID. This is the deduplication key (see Step 4).
  • type - "income" (default) or "expense" to push costs like ad spend.
  • status - "completed", "pending", "refunded", or "failed".
  • tax and fee - tax collected and payment processing fee. CRM Solid computes net as amount minus fee automatically.
  • customer.email - enables automatic CRM contact matching (see Step 6).

A successful response returns HTTP 200 with the created or updated ledger entry ID.

Step 4: Verify idempotency with a duplicate post

Budget: 2 minutes. POST the exact same payload again (same externalId). Open Finance > Revenue sources > (your source) and confirm the event count is still 1, not 2. Then change the amount or status and post again; the existing entry should update, not duplicate.

This behavior is intentional and permanent. Re-posting the sameexternalId is the correct way to update a sale - for example, marking a pending order as completed, or applying a refund. It also means your site can retry failed HTTP requests without risk of double-counting revenue.

Step 5: Configure pull mode

If you chose pull mode, the source detail screen shows a pull settings tab instead of an API key tab. Fill in:

  • Feed URL: the endpoint on your site that returns sale events. CRM Solid will GET this URL on the polling interval. The response must be JSON with an events array and optionally a cursorfield for pagination.
  • Polling interval: how often CRM Solid fetches. Choices range from every 5 minutes to every 1440 minutes (once per day). Near-real-time reporting needs 5-15 minutes; daily batch reporting is fine at 60+ minutes.
  • Authentication: none, a bearer token, or a custom HTTP header name and value. Credentials are stored encrypted.

A minimal feed response looks like this:

{
  "cursor": "cur_88240",
  "events": [
    { "externalId": "ord_5521", "amount": 240, "occurredAt": "2026-06-04T10:00:00Z" },
    { "externalId": "ord_5522", "amount": 59,  "occurredAt": "2026-06-04T11:30:00Z" }
  ]
}

Each run resumes from the last cursor, so CRM Solid only ever fetches new events. Click Test connection to preview the first page of events without ingesting anything. Confirm the shape looks correct, then click Enable pull.

Step 6: Check automatic customer matching

Budget: 1 minute. After your first accepted event, go to Contacts and search for the email address you sent in customer.email.

  • If a contact with that email already existed, open their record. The activity timeline shows the revenue event linked to your source, including the product name and amount.
  • If no contact existed, CRM Solid created one using the name, email, phone, company, country, and city fields from the customer object. You can enrich that contact further from the panel.

Every subsequent sale from the same email address accumulates in the same contact record, giving your sales team a full purchase history alongside the conversation history from other channels.

Step 7: Review synced sales in the Finance ledger

Open Finance > Ledger and filter by your source name. Each row shows the externalId, amount, currency, product, status, and the linked contact. You can click any entry to see the full event payload.

To push costs alongside income, send expense events:

{
  "externalId":  "adspend_2026_06_04",
  "type":        "expense",
  "amount":      55.00,
  "currency":    "USD",
  "occurredAt":  "2026-06-04T00:00:00Z",
  "product":     "Google Ads - June 4"
}

Expense events appear in the same ledger with a negative sign. The profit/loss view in the next step uses both income and expense events together.

Step 8: Monitor per-source profit and loss

Open Finance > Revenue sources > (your source) > Profit and loss. The daily bar chart shows net profit (income minus fees and expense events) per day. Days where costs exceeded income show as negative bars.

Below the chart, the sync log summary for the most recent run shows four counts:

  • Accepted - new events written to the ledger.
  • Duplicates - externalIds already in the ledger; no action taken.
  • Updated - externalIds re-sent with changed fields; existing entry updated.
  • Rejected - events that failed schema validation; click to see the error reason.

If Rejected is consistently above zero, inspect the error reason. Common causes: missing required field, a non-ISOoccurredAt date format, or an unknown currency code.

CRM Solid revenue sources vs other sync options

Honest comparison of the main ways to get external sales into a CRM or finance tool.

CapabilityCRM SolidRecommendedZapierManual CSVStripe-webhook-only
Setup effort
No-code setup path
Requires modifying site code
Data quality
Idempotent deduplication
Rich sale event model (tax, fee, SKU, coupon)
Automatic CRM contact matching
Refund and expense tracking
Reporting
Per-source profit and loss dashboard
Revenue linked to CRM contact history
Sync log with per-run audit trail
Cost
Pricing model
Included in planPer taskFree (labor cost)Stripe fees only

Zapier is ideal for no-code one-off connections but adds per-task cost and lacks deduplication. Manual CSV gives full data but requires ongoing effort and has no contact matching. Stripe-webhook-only works only for Stripe payments and misses non-Stripe revenue.

“We run three WooCommerce stores and a Teachable course site. Before this, revenue reporting was four spreadsheets and a prayer. Now everything lands in one Finance ledger, every buyer is matched to a contact, and I can see actual profit per store after fees. The push setup took me 20 minutes per store.”
Mika Lindqvist
Founder · Nordic Digital Products

Revenue sources FAQ

The eight questions developers and finance-focused founders ask before connecting their first external site.

Use push when your site or app can fire an HTTP request at the moment a sale completes. That gives you the fastest update - the ledger entry appears within seconds. Use pull when you cannot modify your platform code but can expose (or already have) a paginated feed URL. Pull polls on a schedule between 5 minutes and 24 hours, so there is a small delay, but zero code change needed on your site.
Yes, with standard server-side secret management. The raw key is shown exactly once in the panel at creation time, then CRM Solid discards it and stores only a BCrypt hash. Treat it like a database password: store it in an environment variable or secrets manager, never in source control. The key is scoped to revenue events only - it cannot read contacts, send messages, or access any other endpoint.
Nothing bad. The externalId field is the deduplication key. If you POST a sale with an externalId that already exists for that source, CRM Solid updates the existing entry instead of creating a duplicate. This means retries after network failures are completely safe, and you can re-push a sale to correct its amount, status, or customer fields.
When a sale arrives, CRM Solid looks up the customer.email field against your existing contacts. If a match is found, the sale is linked to that contact record and the contact timeline gains a new revenue event. If no match is found, a new contact is created using the name, email, phone, company, and location fields you included in the payload. Either way, the buyer is always associated to a CRM record.
You pass any ISO 4217 three-letter currency code (USD, EUR, GBP, TRY, etc.) on each event. The Finance ledger stores amounts in the original currency. Totals and profit/loss views aggregate within the same currency per source. Cross-currency conversion is not applied automatically, so keep sources in a single currency if you want a single totals view.
Yes. Set "status": "refunded" on a previously accepted externalId to mark that sale as refunded; the finance dashboard subtracts it from already-counted revenue. You can also send "type": "expense" events (ad spend, shipping costs, etc.) through the same endpoint. The profit/loss chart nets income minus expense events per source.
Use the "Test connection" button inside Finance > Revenue sources > (your source) > Pull settings. It fetches the first page of your feed and shows you a preview of the parsed events without ingesting any data. This lets you confirm that the JSON shape is correct and that authentication works before you commit to live ingestion.
Each pull run (and each push batch) records four counts: Accepted (new events written to the ledger), Duplicates (externalIds already seen, no action taken), Updated (externalIds re-sent with changed fields), and Rejected (events that failed schema validation). Nothing silently disappears - if a sale was not accepted you will see a Rejected count and can inspect the reason.
Ready to ship

Connect your first revenue source in 15 minutes

A 14-day trial includes Revenue sources, the Finance ledger, contact matching, and per-source profit and loss. No credit card required.

Trusted by 2,500+ teams · GDPR-ready · 99.95% uptime

We value your privacy

We use cookies to improve our site, analyze traffic, and personalize ads. You can accept all, reject non-essential, or customize your choices. Read our Cookie Policy.