Is it possible to use the API to attach an existing photo record to an observation?

Just for example, I have this photo of a leaf mining fly: Suppose I want to attach the exact same photo record (174417777) to another observation. Is there a way to do that using the API?

I know that it’s possible to duplicate an observation in the website, and that seems to link the photo records from the original observation to the new observation. But I don’t think that’s being done via the API. When I duplicate via the Android app, it seems to create an entirely new photo record (by uploading a copy of the photo) to go with the new observation record. So it’s not possible in the latter case to see that a photo is linked to 2 different observations. Also, the new photo record lacks the metadata from the original record, and it may be a smaller version of the photo as well.

If it is possible to link existing photo records to observations via the API, then it would be possible to create third-party apps to do the following:

  • in a case where several photos of the same organism (at roughly the same time) are loaded as separate single-photo observations, merge these observations into a single observation
  • in a case where photos of many organisms are loaded together into one observation, carve out the photos into separate observations without having to re-upload the photos
  • in a case where a photo is accidentally attached to the wrong observation, move the photo to the correct observation without having to re-upload the photo
  • duplicate an observation without having to re-upload the photos
  • in a case where photos are orphaned, attach them to an observation without having to re-upload the photos. (this might be useful for folks with limited internet connections or limited RAM whose bulk uploads frequently fail. it might be possible to more gracefully recover from such a failure without having to redo the entire bulk upload.)

I had a look for something like this a while ago, but couldn’t find any way to do it.

At the time, I was convinced there must be something, since the API has a /photos endpoint for uploading photos independently of observations - that, is of explicitly creating “orphan” photos. I tried this out, hoping that either the response or the resulting record might offer some clues as to how to make use of it, but it was no help. What are the intended use-cases for this API, if the photo-record can’t be subsequently associated with anything?


i had the same thought process. i thought maybe it was just laying the groundwork for a (future) way to associate photos to observations, or maybe it’s used to create photos that aren’t necessarily tied to observations, such as this one (, which serves as the main taxon photo for Homo sapiens? but who knows?

1 Like

Yes, I also thought of taxon photos - but I couldn’t see any way to directly use an orphan photo for that purpose.

I spent a bit of time trying to figure this out. No luck yet, but the best clue I have so far is the multipart form data sent by the observation edit page ({observation_id}/edit). Open up your dev console, edit an observation, and take a look at the request it sends. It uses the older observation endpoint (POST{observation_id}), and includes:

Content-Disposition: form-data; name="_method"

I see that _method parameter mentioned in the API docs, but it doesn’t mention patch as a valid value, or that you can POST to that endpoint.

Anyway, for existing photos on the observation, you’ll see the site sends form fields like:

Content-Disposition: form-data; name="local_photos[{observation_id}][]"

I tried a bunch of different variations of endpoints, HTTP methods, and formats of specifing local_photos with a photo ID in form data, request parameters, and JSON body, but no luck yet. It’s also possible that this can only be used to remove existing photos from an observation, not add new ones. See the note on the ignore_photos parameter in the API docs

1 Like

isn’t that just uploading a new photo and attaching the new photo record to the observation? can you specify a URL reference (to an existing photo record)?

I thought the interesting part there was that it uses a photo ID instead of a file as the value for local_photos. That seems to be its way of telling the API, “keep these photos on the observation.” If you remove that from the request (and don’t set ignore_photos=1), the photo will be removed from the observation. I was hoping that could also be used to associate a different photo with the observation by photo ID, or that similar syntax would work on a different endpoint.

1 Like

hmmm… ok. i see what you’re looking at. so the idea is basically that if you PUT without setting ignore_photos=1, then maybe setting local_photos with specific photo record IDs will associate those photo records with the observation?..

when i start with 2 photos on an observation and uncheck one of the photos in the edit screen to delete it, i see that it sets local_photos with filename="" and also local_photos = the remaining photo ID. so i wonder if that’s clearing out all the photos and then reattaching the photo that should remain?

UPDATE: i tested various commands, and i can’t seem to get the PUT to attach a photo using local_photo, though i am able to update other parts of the observation… so good lead, but no success on my end either.

UPDATE: after trying several variations of commands, i was able to execute a cURL command from the Windows command prompt that attached an existing photo onto a blank observation. so it is possible to do this via the API.
curl "" -X "PUT" -H "Content-Type: application/json" -H "Accept: application/json" -H "Authorization: JWT" -d "{\"local_photos\":{\"107163770\":[179447766]}}"

thanks for the lead @jcook!

after a little more testing, here’s what i see:

  1. when using PUT /v1/observations/{obsID} to attach existing photos:

    • the payload must not include "ignore_photos":1
    • the payload of the request must include "local_photos":"{obsID}":[{comma-separated list of photoIDs}]
    • the list of photoIDs must include all photos that need to be included in the observation, including photos already attached to the observation. (for example, if obs A includes photos X and Y, and you want to add Z, then list of photos in your PUT must be [X,Y,Z].
      • if you do not include a photo in the list, it will be dropped from the observation, and photos that dropped from the observation and are not tied to any other observations will be immediately deleted. (for example, if obs A includes photos X and Y, which are tied only to A, and you PUT only [Z], obs A will end up with only Z, and X and Y will be gone. in other words, you need to be careful about accidentally orphaning photos, since orphans are immediately purged.)
    • the system is smart enough to ignore photos that do not belong to you. so you cannot attach someone else’s photos to your observation.
    • the system is smart enough to ignore updates on observations that do not belong to you.
  2. i don’t think it’s possible to attach existing photo records while using POST /v1/observations (to create a new observation). so i think that means that you’d have to create a new observation first and then come back and PUT /v1/observations/{obsID} to add the existing photos to the new observation.

1 Like

Nice! I’m glad you were able to figure that out. I think I might find that useful at some point myself.

1 Like

@agoranomos – i was looking through recently created apps in the system, and i noticed you had one in development that is intended to do some of the things i was contemplating. it looks like the effort is on the backburner, but were you thinking returning to it in the next few months or so? if not, i was thinking of making my own thing to copy or move photos at some point.

1 Like

Yep I’ve been meaning to get back to it for a while. However I can’t see me getting to it for the next few months at least as my free time has all but gone for the moment.
The local_photos thing looks like just what I’d need when I do get around to getting back to it though!

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.