# Ramp Integration

> Corporate card expense tracking and reimbursement automation with Ramp.

- **Category:** Integrations
- HTML version: https://www.ondayzero.com/docs/guides/ramp
- All guides: https://www.ondayzero.com/docs/guides/index.md
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md

---

# Ramp Integration

Connect your Ramp corporate card account for automated expense categorization, reimbursement tracking, and journal entry creation.

> The `/api/v1/ramp/*` endpoints below work with an API token but are not part of the public API Reference — they back DayZero's own Integrations page and may change. Synced activity lands in the public [Journal Entries](/docs/guides/journal-entries), [Transactions](/docs/guides/transactions) and [Bills](/docs/guides/bills) endpoints, which is where integrations should read from.

## What Gets Synced

| Data | Description |
|------|-------------|
| Card transactions | Expense journal entries with category mapping |
| Reimbursements | Employee reimbursement tracking as AP |
| Merchants | Merchant name normalization |
| Categories | Ramp category to GL account mapping |
| Receipts | Receipt and memo data for audit trail |

## Connect Ramp

### OAuth (Recommended)

From the Integrations page in DayZero, click **Connect Ramp**. You'll be redirected to Ramp to authorize access.

Or via API:

```bash
curl "https://api.ondayzero.com/api/v1/ramp/connect-url" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"
```

The response includes a `connect_url`. Redirect the user to that URL to begin the OAuth flow. After authorization, DayZero stores the connection and begins syncing transactions.

### Client credentials (Bring your own Ramp Developer App)

Use this when your business created its own Ramp Developer App (Company → Developer → Create New App) with the **Client Credentials** grant type enabled.

From the Integrations page, enter your **Client ID** and **Client Secret** and click **Connect Ramp**.

Or via API — the body must be a flat JSON object (not wrapped in `data`):

```bash
curl -X POST "https://api.ondayzero.com/api/v1/ramp/connect-with-credentials" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{"client_id":"ramp_id_...","client_secret":"..."}'
```

Required Ramp app setup:

1. Grant type: **Client Credentials**
2. Scopes: configure the scopes your integration needs in the Ramp Developer Console (e.g. `transactions:read`, `business:read`, `cards:read`, `users:read`, `departments:read`)
3. Copy the Client ID (`ramp_id_...`) and Client Secret from the app settings

When Ramp refuses the connection, the endpoint answers with Ramp's own reason
rather than a generic failure:

- `400 INTEGRATION_079` — Ramp rejected the Client ID / Client Secret pair.
- `400 INTEGRATION_076` — the token was issued but is missing
  `business:read` / `transactions:read`; the message lists the scopes DayZero
  detected on it.
- `400 INTEGRATION_080` — Ramp rejected the token request for some other
  reason (e.g. the Client Credentials grant type is not enabled); the message
  quotes Ramp's `error_description`.
- `503 INTEGRATION_080` — Ramp was rate-limiting or unavailable. Retry.

## Automatic Accounting

When a corporate card transaction occurs, DayZero creates journal entries:

- **Card purchase**: Debit Expense Account / Credit Ramp Card Payable
- **Card payment**: Debit Ramp Card Payable / Credit Cash
- **Reimbursement approved**: Debit Expense Account / Credit Reimbursement Payable
- **Reimbursement paid**: Debit Reimbursement Payable / Credit Cash

A card issued against a partner credit line (a lender's card program on its Ramp account, managed by DayZero; see [Partner Credit Lines](/docs/guides/credit)) is the exception. Spend on it is the merchant's draw on the line, not the business's own spending: it reaches the credit ledger as a loan from Ramp's webhook whether or not accounting sync is switched on, and it is never stored among the business's Ramp transactions or booked as its expense against Ramp Card Payable, by the webhook or by the scheduled sync (so a journal-entry backfill cannot book it later either). Every other card's transactions are handled as above.

Expense accounts are mapped from Ramp's category data. You can customize the category-to-GL mapping in Settings.

## Connection Status

```bash
curl "https://api.ondayzero.com/api/v1/ramp/status" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"
```

Returns `connected`, `healthy`, `last_synced_at`, `last_sync_error`, `transaction_count`, the Ramp business name/ID, whether the connection `uses_own_credentials`, a `scope_status` breakdown (granted vs. missing scopes) and the current `sync_config`.

## Sync Configuration

`GET /api/v1/ramp/sync-config` returns what is synced and how often; `PUT` the same shape to change it. Every field is optional on update:

```bash
curl -X PUT "https://api.ondayzero.com/api/v1/ramp/sync-config" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "auto_sync_enabled": true,
    "auto_sync_interval_hours": 6,
    "sync_from_date": "2026-01-01",
    "sync_transactions": true,
    "sync_reimbursements": true,
    "sync_bills": true,
    "sync_bill_payments": true,
    "sync_transfers": false,
    "sync_cashbacks": false,
    "sync_statements": false
  }'
```

Restrict the scope with `sync_card_ids`, `sync_department_ids` or `sync_user_ids` (Ramp IDs — `GET /api/v1/ramp/available-filters` lists the options), or bound the window with `sync_from_date` / `sync_to_date`. By default only transactions Ramp's accounting queue marks *sync ready* (coded and approved) are pulled; set `sync_all_cleared_transactions: true` to pull every cleared card transaction — useful for businesses that don't code spend in Ramp. Uncoded rows book to Uncategorized Expense and can be categorized in DayZero.

## Manual Sync

Trigger a manual sync of recent transactions and reimbursements:

```bash
curl -X POST "https://api.ondayzero.com/api/v1/ramp/sync" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"
```

`POST /api/v1/ramp/bills/sync` pulls Ramp Bill Pay bills on their own, and `POST /api/v1/ramp/backfill-journal-entries` creates journal entries for any already-synced transactions that are missing one. `GET /api/v1/ramp/balance` returns the card program's current balance.

## Ramp as an accounting destination

DayZero can also register itself as Ramp's accounting provider so that Ramp users code transactions against DayZero's chart of accounts inside Ramp: `POST /api/v1/ramp/accounting/setup` registers the provider, `POST /api/v1/ramp/accounting/push-coa` pushes the chart of accounts, and `POST /api/v1/ramp/accounting/mark-synced` (`{"object_ids": [...], "sync_type": "TRANSACTION_SYNC"}` — or `REIMBURSEMENT_SYNC`, `BILL_SYNC`, etc.) tells Ramp which objects have been booked. The regular sync does this automatically for what it books.

## Webhooks

Nothing to set up: when you connect, DayZero registers a webhook subscription
on your Ramp account pointing at its own endpoint and answers Ramp's setup
challenge automatically. Ramp issues a signing secret per subscription, so each
business that brings its own Developer App gets its own. Disconnecting removes
the subscription.

If your Ramp app can't manage webhooks, connecting still succeeds — the
integration falls back to scheduled polling, just with more delay before a
transaction appears.

DayZero processes the following Ramp webhook events in real time:

| Event | Action |
|-------|--------|
| `transactions.authorized` | Records the pending card transaction |
| `transactions.cleared` | Creates the expense journal entry, except on a card that belongs to a partner credit line: that purchase becomes a loan on the line instead, and nothing is stored or booked as the operator's expense (Ramp's other transaction events for it are ignored too) |
| `transactions.declined` | On a partner-credit card, puts the loan of a transaction already recorded as cleared on a void hold; ignored otherwise |
| `transactions.ready_for_review` | Updates the stored transaction record |
| `transactions.ready_to_sync` | Updates the stored transaction record |
| `bills.created` | Creates the bill in the Bills module |
| `bills.approved` | Updates bill approval status |
| `bills.paid` | Creates the bill payment journal entry |
| `bills.rejected` | Updates bill status |

Ramp webhook payloads carry only the resource ID, so DayZero fetches the full
record from the Ramp API when an event arrives. Events may arrive out of order
and are retried up to 10 times; DayZero de-duplicates on the event `id`.

## Disconnect

```bash
curl -X DELETE "https://api.ondayzero.com/api/v1/ramp/disconnect" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"
```

Removes stored credentials and disconnects the Ramp integration from the business.
