Download the PHP package coyshdigital/beaconcrm-php without Composer

On this page you can find all versions of the php package coyshdigital/beaconcrm-php. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package beaconcrm-php

Beacon CRM for PHP

A PHP client for the Beacon CRM API.

Beacon generates its API documentation from each account's own database configuration, so no two accounts look alike. This library reads your schema at runtime and shapes values against it, rather than hard-coding record types and fields that would only fit one account.

Features

Requirements

Installation

Authentication

In Beacon, go to Settings > API keys and create a key. Only an administrator can create one, and the key is shown once, when you create it. Copy it straight away. If you lose it, revoke it and make a new one.

Your account ID is the number in your Beacon API URL:

Keep both out of your code:

A Beacon key grants full access to the account. Put it in an environment variable or a secrets manager, never in code or version-controlled config.

Discovering the schema

EntityType gives you:

Method What you get
fields() Every field, keyed by field key
field('emails') One field. A part handle such as name:first resolves to its parent
writableFields() Fields Beacon will accept a write to
mappableFields() Fields writable from a single plain value, which is the set worth showing in a mapping UI

Field gives you label, type (a FieldType), rawType, options(), allowsMultiple(), includesTime(), isWritable() and isMappable(). For a record link, linksTo() names the record types it may point at.

Creating records

Build the body with payload(). It shapes each value against the field it is going to:

entitiesWithSchema() fetches the record type's schema once and caches it for the life of the client. If you already have the EntityType, pass it to entities() and nothing is fetched. entities('person') with no schema also works, and sends values exactly as given, which is what you want if you are shaping them yourself.

Arrays work anywhere Beacon takes multiple values:

Reading records

Updating and upserting

An update leaves any field not in the payload untouched. Note the verb: Beacon takes a PATCH here and answers a PUT with a 404.

Upsert creates a record, or updates the one whose lookup field matches. It is the documented way to avoid duplicates from repeat submissions:

The lookup field has to be genuinely unique in your account, and it has to carry a value in the payload. Otherwise nothing can match and every call creates another record. That case is caught before the request goes out:

An email address is the obvious key for people, but it is also mutable. For migrations and repeatable imports, a stable legacy or external ID makes a better one.

Listing records

Listing lives at the plural entities/{type}, unlike every single-record operation. The response reports the full match count alongside one page of results, and each result arrives in its own {entity, references} envelope. entities() unwraps them:

Beacon's own default page size is 200. To walk everything without holding it in memory, each() pages for you:

Pass archived: true to include archived records. On a real account that can be a large jump, since archived records can outnumber live ones.

Set populate: false for any bulk read. Linked-record data makes responses substantially bigger.

No search endpoint

Beacon's guide describes a filtering system, but there is no corresponding API endpoint. entity/{type}/search, /list and /filter all return a 404. Filter a list client-side, or use request() if your account exposes something this library does not model.

Linking records

A "point to another record" field — Beacon's reference type — holds a list of record IDs. The one thing to know before writing one:

A write to a link field replaces the whole list. It does not append. Send ['c_church_admins' => [$personId]] and every other admin is silently dropped.

So adding a link means reading the list, merging, and sending it back whole. link() does that:

link() and unlink() return null when the links were already as asked, so nothing was sent. setLinks() always writes, and is the only one of the three that needs no read first.

Beacon checks the target type and the cardinality, and reports both as an HTTP 500 with the detail in error.raw:

Those numbers are record type IDs. linksTo() turns them into keys:

Note also that a link takes integers. A numeric string is rejected with 0 must be of integer type, and a bare integer outside a list with must be of array type. Values built through payload() are cast for you.

Finding the record to link to

A link field takes an ID, but the value in hand is usually a name. There is no search endpoint, so there are two ways across:

resolveId() is an upsert, so it is a single request and is what you want when handling a value someone typed. The trade-off is that a typo creates a record rather than failing. findBy() never creates, but costs one request per 200 records — on a type holding 5,000 records a miss is 25 requests, against a rate limit of 300 a minute. It compares case-insensitively, and knows that a stored email is [{"email": "…"}] rather than a bare string.

Beacon's Relationships feature is not in the API

Beacon has a second, separate way to connect records — Relationships, with types such as Employee and Trustee, reciprocal sides, and start and end dates. It is not exposed by the API at all, and this library cannot reach it. Beacon says so directly, and probing a live account confirms it: every candidate endpoint is absent.

The schema mentions relationships only as opaque layout IDs (entity_type_relationship_blocks), which no endpoint resolves.

To manage a connection programmatically, use a point-to-another-record field instead. The only other route is Beacon's CSV relationship import, which cannot be re-run to amend what it created.

Probing Beacon for endpoints yourself? An unknown top-level path does not 404 — it accepts the connection and never answers. With retries on, twenty such paths look exactly like an outage. Use RetryPolicy::none() and a short timeout, and probe a known-good path alongside as a control.

Exports

Trigger a CSV export from a saved export template, poll until it finishes, then download from the signed URL:

Download URLs expire after an hour, though the data is kept for seven days. Poll again for a fresh one. Beacon describes these endpoints as early access and does not list them in its main developer documentation.

Field shaping

Beacon expects a different JSON shape for each field type. EntityPayload converts your values:

Beacon field type What gets sent
Short text, long text, URL The value as-is
Person name An object of name parts, with full derived if you set only the parts
Email [{"email": "...", "is_primary": true}]
Phone [{"number": "...", "is_primary": true}]
Location [{"address_line_one": "...", "is_primary": true}], a list even for single-address fields
Drop-down An array of values, even for single-select fields
Record link An array of integer Beacon record IDs, even for single links. A write replaces the whole list — see Linking records
Checkbox A JSON boolean
Number, percent, rating A JSON number
Currency An object, {"value": 25.5}
Date An ISO date such as 2026-07-21. Read back, Beacon returns a full ISO 8601 timestamp

Person names are addressed one part at a time (name:full, name:first, name:last, name:middle, name:prefix) and reassembled into a single object when the payload is built. Set only first and last and full is derived, which matters because full is what Beacon shows throughout its UI.

Addresses

An address is a contact point, exactly like an email or a phone number, so Beacon takes a list of address objects even where the field holds only one:

Set a bare object and this library wraps it for you, because getting that wrong is unusually expensive: Beacon answers with an HTTP 500 carrying a leaked backend error, Cannot assign to read only property '0' of object '[object String]', which reads like an outage rather than a payload problem.

Addresses can also be addressed one part at a time, which is what lets a flat mapping UI fill one in:

The writable parts are address_line_one, address_line_two, address_line_three, city, region, postal_code, country, country_code and notes. Beacon rejects any other key outright — note postal_code rather than postcode — and sets latitude, longitude and contact_point_id itself, though it accepts them back unchanged, so a value read from Beacon can be modified and written straight back.

Fill in either country or country_code and Beacon derives the other. Geocoding happens server-side. A plain string is treated as the first address line, mirroring how a bare person name becomes full.

A field's allowsMultiple() says whether more than one address is permitted; the payload is a list either way. Writes replace the whole list rather than appending to it.

Currency fields do not take a plain number. Beacon wants an object, and amounts are in major units, so 25.5 means £25.50 rather than 25.5 pence. Send a bare number and Beacon accepts the request with a success response and then stores nothing. The amount disappears with no error anywhere. This library always sends the object form, but keep it in mind if you write to Beacon from anywhere else.

The currency code is left off deliberately, so Beacon applies your account default. Its response echoes the value back with the currency filled in:

Empty values

Empty values (null, '', []) are skipped rather than sent, so a blank optional field cannot overwrite data Beacon already holds. 0 and false are real values and are sent.

Fields you cannot write

mappableFields() leaves out fields that cannot be written from a plain value:

Error handling

Every failure is a BeaconException. The subclasses tell you what to do about it:

Exception When Retried
AuthenticationException 401 or 403. Key revoked, mistyped, or wrong account No
ValidationException 400, or a 5xx carrying Beacon's error.raw detail No
NotFoundException 404. No such account, record type or record No
RateLimitException 429. Over the rate limit Yes
ServerException A bare 5xx Yes
TransportException No HTTP response at all: DNS, timeout, TLS Yes
InvalidPayloadException Caught before sending. Nothing was written n/a
ConfigurationException Missing account ID or API key n/a

Why a 500 can be a validation failure. Beacon reports many validation problems with a 500 status and the real cause in error.raw, while message stays generic. Those requests will never succeed as sent, and retrying a create would duplicate the record. So a 5xx carrying error.raw becomes a ValidationException and is never retried. A bare 5xx with no such detail is treated as transient.

Rate limits and retries

Beacon allows 300 requests a minute, or 60 for bulk operations, and answers a breach with a 429. The default policy makes 3 attempts with exponential backoff and jitter, honouring Retry-After when Beacon sends it:

Describing a request without sending it

Every method that sends has a ...Request() twin that returns an unsent Request:

This is for host frameworks that wrap HTTP in their own events, logging, proxy settings or test modes. The Formie Beacon CRM plugin for Craft CMS uses it to shape payloads here while letting Formie do the sending, which keeps its integration logging and payload events working.

Anything else

Beacon generates its API per account, so your account may expose endpoints this library does not model. Paths are relative to .../v1/account/{accountId}/:

Endpoint confidence

Beacon's full API documentation is generated per account and sits behind a login. These endpoints have been exercised against a live account:

Endpoint Purpose
GET entity_types Read the account schema
POST entity/{type} Create a record
GET entity/{type}/{id} Read a record
PATCH entity/{type}/{id} Update a record
PUT entity/{type}/upsert Create or update on a lookup field
GET entities/{type} List records, with page and per_page

The export endpoints (POST entity_export/trigger and GET entity_exports) are documented by Beacon as early access and have not been exercised here.

Some paths that look obvious do not exist, in case you were about to try them:

Note that an unknown top-level path does not 404. Beacon accepts the connection and never answers, so the request times out — which is worth knowing before you probe anything yourself.

Corrections from other accounts are welcome, especially for the export endpoints.

Testing

The test suite runs against mocked HTTP using an invented schema. No real account's field keys or option values appear in this repository.

Contributing

Issues and pull requests are welcome at Coysh-Digital/beaconcrm-php.

License

MIT. See LICENSE.md.

This is an independent library. It is not affiliated with or endorsed by Beacon.


All versions of beaconcrm-php with dependencies

PHP Build Version
Package Version
Requires php Version >=8.2
ext-json Version *
guzzlehttp/guzzle Version ^7.5
psr/http-message Version ^1.1 || ^2.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package coyshdigital/beaconcrm-php contains the following files

Loading the files please wait ...