Skip to main content
The Pay processing API is for your backend. Complete access and keys and the Payframes integration first. All identifiers below are examples; use IDs returned for your own organization.

Authentication and conventions

Base URL: https://api.wegive.com. Send these headers on requests:
Use your live secret key for live payments. The secret key determines the organization and payment mode. Browser tokenization and backend processing must use matching organization and mode credentials. Transaction and recurring-plan creation additionally require an Idempotency-Key header and a valid fraudSessionId in the body. Forward the initiating browser’s User-Agent on processing requests, retaining it for retries. See the backend guide. Amounts are integer minor units. 5000 represents 50.00 for a two-decimal currency. Optional currency must match the organization’s ISO currency code. The API applies supported amount and account limits; handle validation responses rather than assuming every positive amount is accepted. Dates use YYYY-MM-DD; timestamps in responses use ISO 8601. Optional response fields may be absent or null. Preserve identifiers returned by WeGive and tolerate additional response fields.

Endpoints

The documented Pay API does not expose a transaction polling, refund, or recurring-plan update endpoint. Reconcile payment records in WeGive or through the reporting integration agreed for your account. Do not invent a GET /api/pay/transactions/{id} URL.

One-time donation with inline card details

This is the shortest server-side charge flow. Post the values from Payframes, donor details, and billing information to POST /api/pay/transactions:
Supply all three tokens fields. donor.email, cardholder.name, and cardholder.zip are required for this shape. donor.phone and cardholder.state are optional. Pass the tokenization result unchanged; do not send raw card numbers or security codes. Example 200 response:
Check data.status as well as the HTTP status. pending or processing is not confirmed success. Failed or other non-success transaction states must not be displayed as completed donations. donor or card may be null; bank transactions do not have a card object. Retain data.id for reconciliation.

By-reference donation

Use this flow when your backend needs explicit customer, profile, and payment method records, including when creating recurring plans.

1. Find or create the customer

POST /api/pay/customers accepts required email and optional phone:
Example 200 response:
The response contains only id and email, whether the customer is new or already exists, including when your organization has a giving profile for them. Read your organization’s contact details through the profile endpoints below. The optional phone initializes a new customer only; it does not update an existing customer’s WeGive account. Email lookup and profile creation are not donor authentication or permission to use a person’s saved payment methods.

2. Find or create the giving profile

You can first call GET /api/pay/customers/123/profiles, which returns a data array. An empty array means no visible profiles were found. For an individual, send POST /api/pay/customers/123/profiles:
For a company, use type: "company" and required companyName instead of the individual’s required first and last names. email and phone are optional. The 200 response wraps a profile under data, with id, type, name, firstName, lastName, email, phone, organizationId, userId, and createdAt. Save its id. Creation can return an existing matching profile; it is not an endpoint for overwriting an existing profile’s details.

3. Attach the freshly tokenized payment method

For a card, send POST /api/pay/customers/123/cards:
The 200 response contains data.id, type: "card", brand, last4, expMonth, expYear, ownership identifiers, and createdAt. Keep the returned ID for this attempt. Do not create a new card record every time an uncertain charge is retried. For an approved bank-tokenization integration, send POST /api/pay/customers/123/banks:
bankholder.name is required; zip is optional. The 200 response includes data.id, type: "bank", bankName, last4, ownership identifiers, and createdAt. This is the approved bank-method API flow; the Payframes SDK itself only mounts card fields. Obtain the correct tokenization integration from WeGive. Create a fresh payment method for a new donor-authorized donation. Do not treat these endpoints as permission to build an unrestricted saved-wallet charging service. WeGive manages the payment method’s use by a recurring plan.

4. Submit the donation

Send POST /api/pay/transactions with a stable idempotency key:
Supply paymentMethod.type and id together. Use bank for a bank method. The profile and method must be authorized for the same customer relationship and organization. Choose either the inline or by-reference shape, not both. The response uses the same transaction shape as the inline flow.

Recurring plans

Create the customer, profile, and payment method first. Recurring-plan creation uses by-reference inputs and requires its own idempotency key and valid fraud session. Send POST /api/pay/recurring-plans:
recurringFrequency accepts daily, weekly, 1_and_15, bimonthly, monthly, quarterly, semiannual, or yearly. Optional startDate and endDate use YYYY-MM-DD; supply both when setting an end date. Omitting startDate starts today and can charge immediately. To schedule without charging today, pass a future start date agreed with the donor. Do not call /transactions first to take the same initial payment. Setting frequency: "recurring" on a transaction does not create a recurring schedule; use this recurring-plan endpoint to create the plan. A 201 response contains data for the plan and initialTransaction for a first payment, or null when no payment was taken. An abbreviated example for a future start is:
Plan responses also include organizationBrandId, pausedAt, pausedUntil, coverFees, feeAmount, anonymous, isTaxDeductible, attribution identifiers, createdAt, and updatedAt. Note the response names frequency, endsAt, and isTaxDeductible, which differ from request names. Check both data.cancelled and initialTransaction.status before confirming the plan to the donor. A first-payment failure can return a cancelled new plan. An HTTP 201 alone does not prove an initial payment succeeded. Read a plan with GET /api/pay/recurring-plans/789. List a customer’s active, non-cancelled plans with GET /api/pay/customers/123/recurring-plans; its response is a data array. Cancel with DELETE /api/pay/recurring-plans/789:
Cancellation stops future scheduled donations. It is not a refund and does not reverse a payment already in progress. Changing a schedule or payment method is not exposed as a Pay API update operation; manage those changes through WeGive.

Optional donation fields

These fields apply to transaction and recurring-plan creation unless noted: SDK pop-up options use names such as campaignId. Backend requests use nested objects such as "campaign": { "id": 123 }; do not copy all pop-up options directly into the API body. For custom-checkout UTM attribution, forward the validated values from pay.getAttribution() as top-level utm_* fields on the transaction request. Reporting availability follows your account’s tracking settings.

Idempotency and retries

An idempotency key identifies one donor-authorized attempt. Generate it on your backend and save it before the first request. Use a nonempty unique value of at most 255 characters. Transaction and recurring-plan creation require it. Do not assume this protection applies to every other POST endpoint. For a retry, keep all of these unchanged:
  • The original secret-key identity.
  • The HTTP method and endpoint path.
  • The Idempotency-Key header.
  • The exact serialized request-body bytes, including token and fraud-session values.
Store the serialized JSON once. Reformatting whitespace, changing key order, adding metadata, regenerating tokens, or refreshing the fraud session can make a retry a different body. Do not build the request again from a changed form. When an attempt has a recorded response, an identical retry returns that response. A reused key with a changed request returns 409. A request still in progress or awaiting reconciliation also returns 409. Read the error to distinguish them. Waiting does not make an uncertain attempt safe to execute under a new key. If a connection times out, you receive a 5xx response, or you cannot establish the payment outcome, retain the attempt and reconcile it. You can retry the exact request under its original key to retrieve a recorded response; if it remains unresolved, contact WeGive with the attempt and transaction identifiers. Never issue a new key merely to get past a conflict. A definitive validation rejection may require corrected inputs and a new donor-authorized attempt after confirming no payment occurred. Replaying the old key can return its original rejection. Do not repeatedly mint sessions or new keys to work around a security block. Coordinate credential rotation with unresolved attempts because deduplication does not carry across secret keys.

Errors

Send Accept: application/json and inspect the response body. Validation errors normally include a message and field-keyed errors object; other failures may only provide a message. Do not rely on a single universal error-code schema. Keep your UI’s payment state separate from HTTP success. Even a 200 or 201 response must be checked for transaction status and, for a plan, its cancellation and initial-payment state.